Чем отличается метод copy() от deepcopy() в Python?

«Чем отличается метод copy() от deepcopy() в Python?» — вопрос из категории Python, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

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

import copy

original = [1, 2, [3, 4]]
shallow_copy = original.copy()  # или copy.copy(original)

# Изменение элемента верхнего уровня затрагивает только копию
shallow_copy[0] = 99
print("Original:", original)  # [1, 2, [3, 4]]
print("Shallow copy:", shallow_copy)  # [99, 2, [3, 4]]

# Изменение ВЛОЖЕННОГО изменяемого объекта затрагивает и оригинал!
shallow_copy[2][0] = 88
print("nAfter modifying nested list:")
print("Original:", original)  # [1, 2, [88, 4]]  <- ИЗМЕНИЛСЯ!
print("Shallow copy:", shallow_copy)  # [99, 2, [88, 4]]

2. Глубокое копирование (deepcopy()): Создает новый составной объект, а затем рекурсивно создает копии всех вложенных объектов. В результате получается полностью независимая копия.

import copy

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

# Изменение вложенного объекта теперь безопасно
deep_copy[2][0] = 88
print("Original:", original)  # [1, 2, [3, 4]]  <- НЕ изменился
print("Deep copy:", deep_copy)  # [1, 2, [88, 4]]

Когда что использовать:

  • copy(): Когда у вас плоская структура (список чисел, строк) или вы намеренно хотите, чтобы вложенные объекты разделялись (например, для экономии памяти, если они неизменяемы).
  • deepcopy(): Когда у вас сложная, вложенная структура (словарь списков, список словарей, пользовательские объекты с атрибутами-списками) и вам нужна полная, независимая копия. Учтите, deepcopy() может быть значительно медленнее и требовательнее к памяти для больших структур.

Важно: Для неизменяемых (immutable) объектов, таких как кортежи, строки или числа, разницы между copy() и deepcopy() нет, так как их нельзя изменить.