Вопрос 12 из 16

Основы Python

Расскажи особенности копирования изменяемых объектов

Показать ответ

Короткий ответ

  • Поверхностное копирование (copy()) создает новый объект, но вложенные объекты остаются ссылками
  • Глубокое копирование (deepcopy()) рекурсивно копирует все вложенные объекты

Развернутый ответ

Копирование изменяемых объектов в Python требует особого внимания, так как простое присваивание создает лишь новую ссылку на тот же объект. Вот основные способы и их особенности:


1. Поверхностное копирование (shallow copy)

Создает новый объект, но вкладывает в него ссылки на те же вложенные объекты.

Методы:

import copy

# Для списков
original = [1, [2, 3], 4]
shallow_copy = original.copy()  # или copy.copy(original) или original[:]

# Для словарей
dict_original = {'a': [1, 2]}
dict_copy = dict_original.copy()

Особенности:

  • Изменения вложенных mutable-объектов затрагивают оригинал
  • Быстрее глубокого копирования
  • Достаточно для одноуровневых структур
original[1].append(5)
print(shallow_copy)  # [1, [2, 3, 5], 4] - вложенный список изменился!

2. Глубокое копирование (deep copy)

Рекурсивно создает новые копии всех вложенных объектов.

import copy

original = [1, [2, 3], 4]
deep_copy = copy.deepcopy(original)

original[1].append(5)
print(deep_copy)  # [1, [2, 3], 4] - копия осталась неизменной

Особенности:

  • Полная изоляция от изменений в оригинале
  • Затратно по памяти и времени для сложных структур
  • Может вызвать проблемы с циклическими ссылками

3. Особые случаи

Копирование сложных структур

data = {
    'items': [1, 2, {'key': 'value'}],
    'config': {'settings': [True, False]}
}
data_copy = copy.deepcopy(data)

Копирование пользовательских классов

class MyClass:
    def __init__(self, x):
        self.x = x

obj = MyClass([1, 2, 3])
obj_copy = copy.deepcopy(obj)

4. Различия методов копирования

Метод Уровень Изменения в оригинала Производительность
Присваивание (=) Нет копирования Всегда видны Мгновенно
.copy() / copy.copy() Поверхностное Видны для вложенных объектов Быстро
copy.deepcopy() Глубокое Не видны Медленно

5. Рекомендации

  • Используйте глубокое копирование для структур с вложенными изменяемыми объектами
  • Для простых списков/словарей достаточно shallow copy
  • Избегайте глубокого копирования для объектов с циклическими ссылками
  • Для пользовательских классов можно определить __copy__ и __deepcopy__
class MyClass:
    def __init__(self, x):
        self.x = x
    
    def __copy__(self):
        return MyClass(self.x.copy())
    
    def __deepcopy__(self, memo):
        return MyClass(copy.deepcopy(self.x, memo))

Правильное копирование особенно важно при работе с многопоточными приложениями и изменяемыми аргументами функций.