- copy — Shallow and deep copy operations¶
- Модуль copy — поверхностное и глубокое копирование объектов
- Модуль Copy в Python
- Зачем нам нужен модуль Copy Python?
- Мелкая копия или Shallow
- Глубокая копия или Deep copy
- Основные принципы работы метода copy() в Python
- Использование copy()
- Поверхностное копирование vs глубокое копирование
- Использование copy() с различными типами данных
- Замена copy() на срезы и конструкторы типов
- Подводные камни использования copy()
- Заключение
copy — Shallow and deep copy operations¶
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other. This module provides generic shallow and deep copy operations (explained below).
Return a shallow copy of x.
Raised for module specific errors.
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):
- A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
- A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
Two problems often exist with deep copy operations that don’t exist with shallow copy operations:
- Recursive objects (compound objects that, directly or indirectly, contain a reference to themselves) may cause a recursive loop.
- Because deep copy copies everything it may copy too much, such as data which is intended to be shared between copies.
The deepcopy() function avoids these problems by:
- keeping a memo dictionary of objects already copied during the current copying pass; and
- letting user-defined classes override the copying operation or the set of components copied.
This module does not copy types like module, method, stack trace, stack frame, file, socket, window, or any similar types. It does “copy” functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the pickle module.
Shallow copies of dictionaries can be made using dict.copy() , and of lists by assigning a slice of the entire list, for example, copied_list = original_list[:] .
Classes can use the same interfaces to control copying that they use to control pickling. See the description of module pickle for information on these methods. In fact, the copy module uses the registered pickle functions from the copyreg module.
In order for a class to define its own copy implementation, it can define special methods __copy__() and __deepcopy__() . The former is called to implement the shallow copy operation; no additional arguments are passed. The latter is called to implement the deep copy operation; it is passed one argument, the memo dictionary. If the __deepcopy__() implementation needs to make a deep copy of a component, it should call the deepcopy() function with the component as first argument and the memo dictionary as second argument. The memo dictionary should be treated as an opaque object.
Discussion of the special methods used to support object state retrieval and restoration.
Модуль copy — поверхностное и глубокое копирование объектов
Операция присваивания не копирует объект, он лишь создаёт ссылку на объект. Для изменяемых коллекций, или для коллекций, содержащих изменяемые элементы, часто необходима такая копия, чтобы её можно было изменить, не изменяя оригинал. Данный модуль предоставляет общие (поверхностная и глубокая) операции копирования.
copy.copy(x) — возвращает поверхностную копию x.
copy.deepcopy(x) — возвращает полную копию x.
Исключениеcopy.error — возникает, если объект невозможно скопировать.
Разница между поверхностным и глубоким копированием существенна только для составных объектов, содержащих изменяемые объекты (например, список списков, или словарь, в качестве значений которого — списки или словари):
- Поверхностная копия создает новый составной объект, и затем (по мере возможности) вставляет в него ссылки на объекты, находящиеся в оригинале.
- Глубокая копия создает новый составной объект, и затем рекурсивно вставляет в него копии объектов, находящихся в оригинале.
Для операции глубокого копирования часто возникают две проблемы, которых нет у операции поверхностного копирования:
- Рекурсивные объекты (составные объекты, которые явно или неявно содержат ссылки на себя) могут стать причиной рекурсивного цикла;
- Поскольку глубокая копия копирует всё, она может скопировать слишком много, например, административные структуры данных, которые должны быть разделяемы даже между копиями.
Функция deepcopy решает эти проблемы путем:
- Хранения «memo» словаря объектов, скопированных во время текущего прохода копирования;
- Позволения классам, определенным пользователем, переопределять операцию копирования или набор копируемых компонентов.
Этот модуль не копирует типы вроде модулей, классов, функций, методов, следа в стеке, стековых кадров, файлов, сокетов, окон, и подобных типов.
Поверхностная копия изменяемых объектов также может быть создана методом .copy() у списков (начиная с Python 3.3), присваиванием среза (copied_list = original_list[:]), методом .copy() словарей и множеств. Создавать копию неизменяемых объектов (таких, как, например, строк) необязательно (они же неизменяемые).
Для того, чтобы определить собственную реализацию копирования, класс может определить специальные методы __copy__() и __deepcopy__(). Первый вызывается для реализации операции поверхностного копирования; дополнительных аргументов не передается. Второй вызывается для реализации операции глубокого копирования; ему передается один аргумент, словарь memo. Если реализация __deepcopy__() нуждается в создании глубокой копии компонента, то он должен вызвать функцию deepcopy() с компонентом в качестве первого аргумента и словарем memo в качестве второго аргумента.
Для вставки кода на Python в комментарий заключайте его в теги
Модуль Copy в Python
В этой статье мы рассмотрим использование модуля Python Copy для выполнения операций глубокого и поверхностного копирования.
Зачем нам нужен модуль Copy Python?
В Python все представлено с помощью объектов. Поэтому во многих случаях нам может потребоваться прямое копирование объектов.
В этих случаях мы не можем использовать оператор присваивания напрямую.
Суть присвоения заключается в том, что несколько переменных могут указывать на один и тот же объект. Это означает, что если объект изменяется с использованием любой из этих переменных, изменения будут отражаться везде.
Следующий пример иллюстрирует эту проблему с помощью изменяемого объекта общего списка.
a = [1, 2, 3, 4] b = a print(a) print(b) b.append(5) # Changes will be reflected in a too! print(a) print(b)
[1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
Как видите, поскольку обе переменные указывают на один и тот же объект, при изменении b изменяется и a !
Чтобы справиться с этой проблемой, Python дает нам возможность использовать модуль копирования.
Модуль Copy в Python является частью стандартной библиотеки и может быть импортирован с помощью следующего оператора:
Теперь в этом модуле мы можем выполнять в основном два типа операций:
Мелкая копия или Shallow
Этот метод используется для выполнения операции неглубокого копирования.
Синтаксис вызова этого метода:
import copy new_obj = copy.copy(old_obj) # Perform a shallow copy
Теперь, поскольку он создает новый объект, мы можем быть уверены, что наш новый объект отличается от старого объекта.
Однако при этом будут сохраняться ссылки на вложенные объекты. Поэтому, если объект, который нам нужно скопировать, имеет другие изменяемые объекты (список, набор и т. д.), он все равно будет поддерживать ссылки на тот же вложенный объект.
Чтобы проиллюстрировать первый пункт, мы попробуем это с помощью простого списка целых чисел (без вложенных объектов!)
import copy old_list = [1, 2, 3] print(old_list) new_list = copy.copy(old_list) # Let's try changing new_list new_list.append(4) # Changes will not be reflected in the original list, since the objects are different print(old_list) print(new_list)
Как видите, если наш объект представляет собой простой список, неглубокая копия не вызывает проблем.
Возьмем другой случай, когда наш объект представляет собой список списков.
import copy old_list = [[1, 2], [1, 2, 3]] print(old_list) new_list = copy.copy(old_list) # Let's try changing a nested object inside the list new_list[1].append(4) # Changes will be reflected in the original list, since the object contains a nested object print(old_list) print(new_list)
[[1, 2], [1, 2, 3]] [[1, 2], [1, 2, 3, 4]] [[1, 2], [1, 2, 3, 4]]
old_list new_list что были затронуты и old_list и new_list !
Если мы должны избегать такого поведения, то надо рекурсивно копировать все объекты вместе с вложенными объектами. Это называется операцией глубокого копирования.
Глубокая копия или Deep copy
Этот метод похож на метод поверхностного копирования, но теперь он копирует все из исходного объекта (включая вложенные объекты) в новый объект.
Чтобы выполнить операцию глубокого копирования, мы можем использовать следующий синтаксис:
import copy new_object = copy.deepcopy(old_object)
Давайте возьмем наш старый пример и попробуем использовать Deep копирование для решения нашей проблемы.
import copy old_list = [[1, 2], [1, 2, 3]] print(old_list) new_list = copy.deepcopy(old_list) # Let's try changing a nested object inside the list new_list[1].append(4) # Changes will be reflected in the original list, since the objects are different print(old_list) print(new_list)
[[1, 2], [1, 2, 3]] [[1, 2], [1, 2, 3]] [[1, 2], [1, 2, 3, 4]]
Обратите внимание, что старый список не изменился. Поскольку все объекты были скопированы рекурсивно.
Основные принципы работы метода copy() в Python
Метод copy() в Python используется для создания копии объекта.
В этой статье мы подробно рассмотрим, как работает этот метод и в каких ситуациях его следует использовать.
Использование copy()
Метод copy() в Python может быть вызван у различных типов объектов, включая списки, словари, множества и другие. Рассмотрим пример его использования на списке:
original = [1, 2, 3, 4, 5] copy = original.copy() print(copy) #[1, 2, 3, 4, 5]
В этом примере метод copy() вызывается у списка original , и результат присваивается новой переменной copy . Теперь copy и original — это два разных списка с одинаковым содержимым.
Поверхностное копирование vs глубокое копирование
Важно понимать, что метод copy() выполняет поверхностное копирование объекта. Это означает, что если объект содержит другие объекты (например, список списков), то в копии будут содержаться ссылки на те же вложенные объекты. Рассмотрим пример:
original = [[1, 2, 3], [4, 5, 6]] copy = original.copy() copy[0][0] = 9 print(original) #[[9, 2, 3], [4, 5, 6]]
В этом примере изменение элемента вложенного списка в copy приводит к изменению в original , потому что copy содержит ссылки на те же вложенные списки.
Если вам нужно создать полностью независимую копию объекта, включая все вложенные объекты, то нужно использовать глубокое копирование. В Python для этого есть функция deepcopy() из модуля copy .
import copy original = [[1, 2, 3], [4, 5, 6]] deep_copy = copy.deepcopy(original) deep_copy[0][0] = 9 print(original) #[[1, 2, 3], [4, 5, 6]]
Использование copy() с различными типами данных
Метод copy() можно использовать с различными типами данных, включая списки, словари и множества.
# List original_list = [1, 2, 3, 4, 5] copy_list = original_list.copy() print(copy_list) # Outputs: [1, 2, 3, 4, 5] # Dictionary original_dict = copy_dict = original_dict.copy() print(copy_dict) # Outputs: # Set original_set = copy_set = original_set.copy() print(copy_set) # Outputs:
Замена copy() на срезы и конструкторы типов
Для списков и некоторых других типов данных, вместо copy() можно использовать срезы или конструкторы типов для создания копий.
# List original_list = [1, 2, 3, 4, 5] copy_list = original_list[:] # or copy_list = list(original_list) # Dictionary original_dict = copy_dict = dict(original_dict) # Set original_set = copy_set = set(original_set)
Эти способы также создают поверхностные копии, как и метод copy() .
Подводные камни использования copy()
Помимо различия между поверхностным и глубоким копированием, важно помнить, что не все типы данных в Python поддерживают метод copy() . Например, числа, строки и кортежи являются неизменяемыми (immutable), и у них нет метода copy() . Попытка вызвать copy() у такого объекта приведет к ошибке:
number = 42 copy = number.copy() # AttributeError: 'int' object has no attribute 'copy'
Заключение
Метод copy() в Python — это удобный инструмент для создания копий объектов. Он работает с различными типами данных, включая списки, словари и множества, и делает поверхностное копирование объектов. При работе с вложенными структурами данных важно помнить о разнице между поверхностным и глубоким копированием и использовать функцию deepcopy() , если необходима полная независимость копии от оригинала.