Язык программирования Python

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

Стандартный модуль copy позволяет создавать копии различных объектов Python. Это изменяемые коллекции (такие как списки и словари) и экземпляры классов, также изменяемые.

Эта статья посвящена тому, как работают объекты в Python и чем они отличаются от понятия “переменные” в других языках.

Перейдем непосредственно к примеру. Рассмотрим следующий список.

a = list(range(5)) print(a)
Code language: PHP (php)
[0, 1, 2, 3, 4]
Code language: JSON / JSON with Comments (json)

Если по какой-то причине мне нужно создать список, равный предыдущему, интуитивно я сделаю следующее.

a = list(range(5)) b = a print(b)
Code language: PHP (php)

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

Список всегда один и к нему можно получить доступ через два разных имени (a и b).

Это можно проверить, просто посмотрев, как изменение элементов одного объекта отражается на другом.

a = list(range(5)) b = a b.append(5) print('Список a', a) del a[2] print('Список b',b)
Code language: PHP (php)
Список a [0, 1, 2, 3, 4, 5] Список b [0, 1, 3, 4, 5]
Code language: CSS (css)

Кроме того, оператор is подтверждает, что это действительно один и тот же объект.

a = list(range(5)) b = a print(a is b)
Code language: PHP (php)
True
Code language: PHP (php)

Но иногда мы действительно хотим создать два одинаковых, но независимых друг от друга объекта, то есть каждый со своим собственным выделенным местом в памяти. Вот тут-то нам и поможет функция copy.copy().

import copy a = list(range(5)) b = copy.copy(a) print(a is b) b.append(5) print('Список a', a) print('Список b', b)
Code language: PHP (php)
False Список a [0, 1, 2, 3, 4] Список b [0, 1, 2, 3, 4, 5]
Code language: CSS (css)

В конкретном случае со списками этот результат также достигается путем применения операции slicing.

a = list(range(5)) b = a[:] print(a is b) print('Список a', a) print('Список b', b)
Code language: PHP (php)
False Список a [0, 1, 2, 3, 4] Список b [0, 1, 2, 3, 4]
Code language: CSS (css)

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

Например, для словарей.

d1 = {"Hello": "Привет", "World": "мир"} d2 = copy.copy(d1)
Code language: JavaScript (javascript)

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

Например, когда у нас есть списки внутри других списков.

import copy a = [[1, 2], [3, 4]] b = copy.copy(a) b[1].append(5) print(a)
Code language: JavaScript (javascript)
[[1, 2], [3, 4, 5]]
Code language: JSON / JSON with Comments (json)

В этом случае a действительно является отдельным объектом от b, но оба содержат внутри себя ссылки на одни и те же объекты: [1, 2] и [3, 4].

print(a[1] is b[1])
Code language: CSS (css)
True
Code language: PHP (php)

Для решения этой проблемы мы используем copy.deepcopy(), которая позволяет копировать все объекты рекурсивно.

a = [[1, 2], [3, 4]] b = copy.deepcopy(a) b[1].append(5) print('a:', a) print('b:', b) print(a[1] is b[1])
Code language: PHP (php)
a: [[1, 2], [3, 4]] b: [[1, 2], [3, 4, 5]] False
Code language: CSS (css)

Этот метод особенно полезен при создании копий экземпляров изменяемых классов (помните, что каждый класс по умолчанию является изменяемым).

Например, рассмотрим следующий класс, который представляет студента и имеет в качестве атрибута список, содержащий предметы, на которые он/она зачислен.

class Student: def __init__(self, subjects): self.subjects = subjects student1 = Student(["Математика", "География"])

Если у нас есть другой студент, который изучает те же предметы, что и студент1, но добавляет некоторые другие, мы должны сделать это:

student2 = copy.deepcopy(student1) student2.subjects.append("Литература")
Code language: JavaScript (javascript)

При выводе обоих значений мы видим, что каждый объект сохраняет свою независимость.

print(student1.subjects) # ["Математика", "География"] print(student2.subjects) # ["Математика", "География", "Литература"]
Code language: CSS (css)

И copy.copy(), и copy.deepcopy() вызывают исключение copy.error, если произошла внутренняя ошибка, и TypeError, если в качестве аргумента передан объект, который не подлежит копированию (например, socket).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *