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

Ответ

В 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() нет, так как их нельзя изменить.

Ответ 18+ 🔞

Э, слушай, а вот эта тема с копированием в питоне — это просто ёперный театр какой-то. Люди думают, что скопировал список — и всё, свободен, а потом у них программа ведёт себя как хитрая жопа, и они охуевают, не понимая, откуда ноги растут.

Короче, есть два главных героя: copy() и deepcopy(). Разница между ними — это как между «чуть-чуть» и «полностью». И если её не понимать, будет вам хиросима и нагасаки в одном флаконе.

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("nПосле изменения вложенного списка:")
print("Original:", original)  # [1, 2, [88, 4]]  <- Бля! И оригинал поменялся!
print("Shallow copy:", shallow_copy)  # [99, 2, [88, 4]]

Видишь? Вложенный список [3, 4] — это один и тот же объект в памяти для обоих. Поменял в копии — ебааать, и оригинал поплыл. Доверия к такому копированию — ноль ебать.

2. Глубокое копирование (deepcopy()) А вот это уже серьёзно. 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(): Когда у тебя структура простая, плоская (список из чисел, строк) или когда тебе нарочно нужно, чтобы вложенные объекты были общими (например, они неизменяемые и память жалко). Но будь готов, что если там что-то mutable затесалось — пиши пропало.
  • deepcopy(): Когда у тебя структура сложная, как мозги после пятницы: список списков, словарь списков, свои классы с кучей атрибутов-списков. Нужна полная независимость — бери deepcopy. Да, он жрёт память и может быть медленным для овердохуища больших структур, но зато спать спокойно.

Важный нюанс: Для неизменяемых объектов (кортежи, строки, числа) похуй, какую копию делать. Их всё равно не изменишь, так что разницы нет. Но как только появляется что-то изменяемое внутри — вот тут и начинается настоящая магия, а точнее, пиздец, если невнимательный.