Копирование объектов, модуль copy на Python

В Python изменяемые объекты нельзя скопировать, присвоив одну переменной другой, так как в этом случае копируется ссылка на объект, а не он сам. В итоге при изменении объекта через одну переменную, изменения видны через другую. Поэтому используются иные способы копирования, если оно действительно необходимо.

У списков, словарей и некоторых других встроенных типов есть метод copy(), создающий их поверхностную копию. В случае поверхностной копии, если объект является составным, то есть включает другие изменяемые объекты, то они не копируются, а копируются только ссылки на них.

Если же требуется полная копия объекта, следует воспользоваться функцией deepcopy() модуля copy. Кроме этой функции там также есть функция copy(), выполняющая поверхностное копирование, аналогичное методам copy() словарей и списков.

Разницу между copy() и deepcopy() иллюстрирует пример:

>>> import copy
>>> nums = [1, 2, 3]
>>> data = {'a': 10, 'b': nums}
>>> data
{'a': 10, 'b': [1, 2, 3]}
>>> data_copy = copy.copy(data)
>>> data_deep = copy.deepcopy(data)
>>> data_copy
{'a': 10, 'b': [1, 2, 3]}
>>> data_deep
{'a': 10, 'b': [1, 2, 3]}
>>> data_copy['a'] += 2
>>> nums[1:1] = [254]
>>> data
{'a': 10, 'b': [1, 254, 2, 3]}
>>> data_copy
{'a': 12, 'b': [1, 254, 2, 3]}
>>> data_deep
{'a': 10, 'b': [1, 2, 3]}

В случае с deepcopy() была создана копия вложенного списка, copy() этого не делает.

Отсутствие переменной у списка вовсе не изменяет ситуацию:

>>> d = {1: [1,2], 2: 10}
>>> c = copy.copy(d)
>>> c
{1: [1, 2], 2: 10}
>>> c[1].append(3)
>>> c
{1: [1, 2, 3], 2: 10}
>>> d
{1: [1, 2, 3], 2: 10}

Оператор is проверяет проверяет ссылаются ли две переменные на один объект, оператор == проверяет равенство значений.

>>> d = {1:2}
>>> c = d
>>> e = d.copy()
>>> d is c
True
>>> d is e
False
>>> d == e
True

С помощью функций модуля copy можно копировать объекты собственных классов:

import copy
class A:
    def __init__(self):
        self.lst = []
a = A()
a.lst.append(10)
b = copy.copy(a)
b.lst[0] = 20
print(a.lst, b.lst)
print(a is b)
print(a)
print(b)

Результат:

[20] [20]
False
<__main__.A object at 0x7f9b5e2bda58>
<__main__.A object at 0x7f9b5e2caac8>

Как мы видим, несмотря на то, что объекты a и b разные, поле lst обоих ссылается на один и тот же список. Чтобы при копировании объекта список был также скопирован, следует использовать функцию deepcopy().

  Создание библиотеки Python: Практическое руководство
Оцените статью
( Пока оценок нет )
Поделиться с друзьями
Python для начинающих
Подписаться
Уведомить о
guest
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x