Мегаобучалка Главная | О нас | Обратная связь


Модуль copy - поверхностное и глубокое копирование объектов



2015-11-23 816 Обсуждений (0)
Модуль copy - поверхностное и глубокое копирование объектов 0.00 из 5.00 0 оценок




Операция присваивания не копирует объект, он лишь создаёт ссылку на объект. Для изменяемых коллекций, или для коллекций, содержащих изменяемые элементы, часто необходима такая копия, чтобы её можно было изменить, не изменяя оригинал. Данный модуль предоставляет общие (поверхностная и глубокая) операции копирования.

copy.copy(x) - возвращает поверхностную копию x.

copy.deepcopy(x) - возвращает полную копию x.

Исключение copy.error - возникает, если объект невозможно скопировать.

Разница между поверхностным и глубоким копированием существенна только для составных объектов, содержащих изменяемые объекты (например, список списков, или словарь, в качестве значений которого - списки или словари):

· Поверхностная копия создает новый составной объект, и затем (по мере возможности) вставляет в него ссылки на объекты, находящиеся в оригинале.

· Глубокая копия создает новый составной объект, и затем рекурсивно вставляет в него копии объектов, находящихся в оригинале.

>>> import copy>>> test_1 = [1, 2, 3, [1, 2, 3]]>>> test_copy = copy.copy(test_1)>>> print(test_1, test_copy)[1, 2, 3, [1, 2, 3]] [1, 2, 3, [1, 2, 3]]>>> test_copy[3].append(4)>>> print(test_1, test_copy)[1, 2, 3, [1, 2, 3, 4]] [1, 2, 3, [1, 2, 3, 4]]>>> test_1 = [1, 2, 3, [1, 2, 3]]>>> test_deepcopy = copy.deepcopy(test_1)>>> test_deepcopy[3].append(4)>>> print(test_1, test_deepcopy)[1, 2, 3, [1, 2, 3]] [1, 2, 3, [1, 2, 3, 4]]

Для операции глубокого копирования часто возникают две проблемы, которых нет у операции поверхностного копирования:

· Рекурсивные объекты (составные объекты, которые явно или неявно содержат ссылки на себя) могут стать причиной рекурсивного цикла;

· Поскольку глубокая копия копирует всё, она может скопировать слишком много, например, административные структуры данных, которые должны быть разделяемы даже между копиями.

 

Функция deepcopy решает эти проблемы путем:

· Хранения "memo" словаря объектов, скопированных во время текущего прохода копирования;

· Позволения классам, определенным пользователем, переопределять операцию копирования или набор копируемых компонентов.

>>> r = [1, 2, 3]>>> r.append(r)>>> print(r)[1, 2, 3, [...]]>>> p = copy.deepcopy(r)>>> print(p)[1, 2, 3, [...]]

Этот модуль не копирует типы вроде модулей, классов, функций, методов, следа в стеке, стековых кадров, файлов, сокетов, окон, и подобных типов.

Поверхностная копия изменяемых объектов также может быть создана методом .copy() у списков(начиная с Python 3.3), присваиванием среза (copied_list = original_list[:]), методом .copy() словарей и множеств. Создавать копию неизменяемых объектов (таких, как, например, строк) необязательно (они же неизменяемые).

Для того, чтобы определить собственную реализацию копирования, класс может определить специальные методы __copy__() и __deepcopy__(). Первый вызывается для реализации операции поверхностного копирования; дополнительных аргументов не передается. Второй вызывается для реализации операции глубокого копирования; ему передается один аргумент, словарь memo. Если реализация __deepcopy__() нуждается в создании глубокой копии компонента, то он должен вызвать функцию deepcopy() с компонентом в качестве первого аргумента и словарем memo в качестве второго аргумента.

Модуль functools

Модуль functools - сборник функций высокого уровня: взаимодействующих с другими функциями или возвращающие другие функции.

Модуль functools определяет следующие функции:

functools.cmp_to_key(func) - превращает функцию сравнения в key-функцию. Используется с инструментами, принимающие key-функции (sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()). Эта функция в основном используется в качестве переходного инструмента для программ, преобразованных из Python 2, которые поддерживали использование функций сравнения.

Функция сравнения - функция, принимающая два аргумента, сравнивающая их и возвращающая отрицательное число, если первый аргумент меньше, ноль, если равен и положительное число, если больше. Key-функция - функция, принимающая один аргумент и возвращающая другое значение, определяющее положение аргумента при сортировке.

@functools.lru_cache(maxsize=128, typed=False) - декоратор, который сохраняет результаты maxsize последних вызовов. Это может сэкономить время при дорогих вычислениях, если функция периодически вызывается с теми же аргументами.

Поскольку в качестве кэша используется словарь, все аргументы должны быть хешируемыми.

Если maxsize установлен в None, кэш может возрастать бесконечно. Также функция наиболее эффективна, если maxsize это степень двойки.

Если typed - True, аргументы функции с разными типами будут кэшироваться отдельно. Например, f(3) и f(3.0) будут считаться разными вызовами, возвращающие, возможно, различный результат.

Чтобы помочь измерить эффективность кэширования и отрегулировать размер кэша, обёрнутая функция дополняется функцией cache_info(), возвращающая namedtuple, показывающий попадания в кэш, промахи, максимальный размер и текущий размер. В многопоточном окружении, количество попаданий и промахов приблизительно.

Также имеется функция cache_clear() для очистки кэша.

 

Оригинальная функция доступна через атрибут __wrapped__.

from functools import lru_cache # Пример получения веб-страницimport urllib.request @lru_cache(maxsize=32)def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = 'http://www.python.org/dev/peps/pep-%04d/' % num try: with urllib.request.urlopen(resource) as s: return s.read() except urllib.error.HTTPError: return 'Not Found' for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991: pep = get_pep(n) print(n, len(pep)) print(get_pep.cache_info())# CacheInfo(hits=3, misses=8, maxsize=32, currsize=8) # Числа Фибоначчи (попробуйте убрать lru_cache) :) @lru_cache(maxsize=None)def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) print([fib(n) for n in range(100)])# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610... print(fib.cache_info())# CacheInfo(hits=196, misses=100, maxsize=None, currsize=100)

@functools.total_ordering - декоратор класса, в котором задан один или более методов сравнения. Этот декоратор автоматически добавляет все остальные методы. Класс должен определять один из методов __lt__(), __le__(), __gt__(), или __ge__(). Кроме того, он должен определять метод __eq__().

Например:

@total_orderingclass Student: def __eq__(self, other): return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower())) def __lt__(self, other): return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))

functools.partial(func, *args, **keywords) - возвращает partial-объект (по сути, функцию), который при вызове вызывается как функция func, но дополнительно передают туда позиционные аргументы args, и именованные аргументы kwargs. Если другие аргументы передаются при вызове функции, то позиционные добавляются в конец, а именованные расширяют и перезаписывают.

Например:

from functools import partialbasetwo = partial(int, base=2)basetwo.__doc__ = 'Convert base 2 string to an int.'print(basetwo('10010'))# 18

functools.reduce(function, iterable[, initializer]) - берёт два первых элемента, применяет к ним функцию, берёт значение и третий элемент, и таким образом сворачивает iterable в одно значение. Например, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) эквивалентно ((((1+2)+3)+4)+5). Если задан initializer, он помещается в начале последовательности.

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) - обновляет функцию-оболочку, чтобы она стала похожей на обёрнутую функцию. assigned - кортеж, указывающий, какие атрибуты исходной функции копируются в функцию-оболочку (по умолчанию это WRAPPER_ASSIGNMENTS (__name__, __module__, __annotations__ и __doc__)). updated - кортеж, указывающий, какие атрибуты обновляются (по умолчанию это WRAPPER_UPDATES (обновляется __dict__ функции-оболочки)).

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) - удобная функция для вызова partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) как декоратора при определении функции-оболочки. Например:

from functools import wrapsdef my_decorator(f): @wraps(f) def wrapper(*args, **kwds): print('Calling decorated function') return f(*args, **kwds) return wrapper @my_decoratordef example(): """Docstring""" print('Called example function') example()# Calling decorated function# Called example functionprint(example.__name__)# exampleprint(example.__doc__)# Docstring

 

 

Модуль os.path

os.path является вложенным модулем в модуль os, и реализует некоторые полезные функции на работы с путями.

os.path.abspath(path) - возвращает нормализованный абсолютный путь.

os.path.basename(path) - базовое имя пути (эквивалентно os.path.split(path)[1]).

os.path.commonprefix(list) - возвращает самый длинный префикс всех путей в списке.

os.path.dirname(path) - возвращает имя директории пути path.

os.path.exists(path) - возвращает True, если path указывает на существующий путь или дескриптор открытого файла.

os.path.expanduser(path) - заменяет ~ или ~user на домашнюю директорию пользователя.

os.path.expandvars(path) - возвращает аргумент с подставленными переменными окружения ($name или ${name} заменяются переменной окружения name). Несуществующие имена не заменяет. На Windows также заменяет %name%.

os.path.getatime(path) - время последнего доступа к файлу, в секундах.

os.path.getmtime(path) - время последнего изменения файла, в секундах.

os.path.getctime(path) - время создания файла (Windows), время последнего изменения файла (Unix).

os.path.getsize(path) - размер файла в байтах.

os.path.isabs(path) - является ли путь абсолютным.

os.path.isfile(path) - является ли путь файлом.

os.path.isdir(path) - является ли путь директорией.

os.path.islink(path) - является ли путь символической ссылкой.

os.path.ismount(path) - является ли путь точкой монтирования.

os.path.join(path1[, path2[, ...]]) - соединяет пути с учётом особенностей операционной системы.

os.path.normcase(path) - нормализует регистр пути (на файловых системах, не учитывающих регистр, приводит путь к нижнему регистру).

os.path.normpath(path) - нормализует путь, убирая избыточные разделители и ссылки на предыдущие директории. На Windows преобразует прямые слеши в обратные.

os.path.realpath(path) - возвращает канонический путь, убирая все символические ссылки (если они поддерживаются).

os.path.relpath(path, start=None) - вычисляет путь относительно директории start (по умолчанию - относительно текущей директории).

os.path.samefile(path1, path2) - указывают ли path1 и path2 на один и тот же файл или директорию.

os.path.sameopenfile(fp1, fp2) - указывают ли дескрипторы fp1 и fp2 на один и тот же открытый файл.

os.path.split(path) - разбивает путь на кортеж (голова, хвост), где хвост - последний компонент пути, а голова - всё остальное. Хвост никогда не начинается со слеша (если путь заканчивается слешем, то хвост пустой). Если слешей в пути нет, то пустой будет голова.

os.path.splitdrive(path) - разбивает путь на пару (привод, хвост).

os.path.splitext(path) - разбивает путь на пару (root, ext), где ext начинается с точки и содержит не более одной точки.

os.path.supports_unicode_filenames - поддерживает ли файловая система Unicode.

Модуль json

JSON (JavaScript Object Notation) - простой формат обмена данными, основанный на подмножестве синтаксиса JavaScript. Модуль json позволяет кодировать и декодировать данные в удобном формате.

Кодирование основных объектов Python:

>>> import json>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])'["foo", {"bar": ["baz", null, 1.0, 2]}]'>>> print(json.dumps("\"foo\bar"))"\"foo\bar">>> print(json.dumps('\u1234'))"\u1234">>> print(json.dumps('\\'))"\\">>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)){"a": 0, "b": 0, "c": 0}

Компактное кодирование:

>>> import json>>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',', ':'))'[1,2,3,{"4":5,"6":7}]'

Красивый вывод:

>>> import json>>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)){ "4": 5, "6": 7}

Декодирование (парсинг) JSON:

>>> import json>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')['foo', {'bar': ['baz', None, 1.0, 2]}]>>> json.loads('"\\"foo\\bar"')'"foo\x08ar'

Основы

json.dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) - сериализует obj как форматированный JSON поток в fp.

Если skipkeys = True, то ключи словаря не базового типа (str, unicode, int, long, float, bool, None) будут проигнорированы, вместо того, чтобы вызывать исключение TypeError.

Если ensure_ascii = True, все не-ASCII символы в выводе будут экранированы последовательностями \uXXXX, и результатом будет строка, содержащая только ASCII символы. Если ensure_ascii = False, строки запишутся как есть.

Если check_circular = False, то проверка циклических ссылок будет пропущена, а такие ссылки будут вызывать OverflowError.

Если allow_nan = False, при попытке сериализовать значение с запятой, выходящее за допустимые пределы, будет вызываться ValueError (nan, inf, -inf) в строгом соответствии со спецификацией JSON, вместо того, чтобы использовать эквиваленты из JavaScript (NaN, Infinity, -Infinity).

Если indent является неотрицательным числом, то массивы и объекты в JSON будут выводиться с этим уровнем отступа. Если уровень отступа 0, отрицательный или "", то вместо этого будут просто использоваться новые строки. Значение по умолчанию None отражает наиболее компактное представление. Если indent - строка, то она и будет использоваться в качестве отступа.

Если sort_keys = True, то ключи выводимого словаря будут отсортированы.

json.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) - сериализует obj в строку JSON-формата.

Аргументы имеют то же значение, что и для dump().

Ключи в парах ключ/значение в JSON всегда являются строками. Когда словарь конвертируется в JSON, все ключи словаря преобразовываются в строки. В результате этого, если словарь сначала преобразовать в JSON, а потом обратно в словарь, то можно не получить словарь, идентичный исходному. Другими словами, loads(dumps(x)) != x, если x имеет нестроковые ключи.

json.load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) - десериализует JSON из fp.

object_hook - опциональная функция, которая применяется к результату декодирования объекта (dict). Использоваться будет значение, возвращаемое этой функцией, а не полученный словарь.

object_pairs_hook - опциональная функция, которая применяется к результату декодирования объекта с определённой последовательностью пар ключ/значение. Будет использован результат, возвращаемый функцией, вместо исходного словаря. Если задан так же object_hook, то приоритет отдаётся object_pairs_hook.

parse_float, если определён, будет вызван для каждого значения JSON с плавающей точкой. По умолчанию, это эквивалентно float(num_str).

parse_int, если определён, будет вызван для строки JSON с числовым значением. По умолчанию эквивалентно int(num_str).

parse_constant, если определён, будет вызван для следующих строк: "-Infinity", "Infinity", "NaN". Может быть использовано для возбуждения исключений при обнаружении ошибочных чисел JSON.

Если не удастся десериализовать JSON, будет возбуждено исключение ValueError.

json.loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) - десериализует s (экземпляр str, содержащий документ JSON) в объект Python.

Остальные аргументы аналогичны аргументам в load().



2015-11-23 816 Обсуждений (0)
Модуль copy - поверхностное и глубокое копирование объектов 0.00 из 5.00 0 оценок









Обсуждение в статье: Модуль copy - поверхностное и глубокое копирование объектов

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Почему двоичная система счисления так распространена?: Каждая цифра должна быть как-то представлена на физическом носителе...
Как построить свою речь (словесное оформление): При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою...
Генезис конфликтологии как науки в древней Греции: Для уяснения предыстории конфликтологии существенное значение имеет обращение к античной...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (816)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.008 сек.)