← Назад к вопросам
В чем разница между глубоким (deep copy) и поверхностным (shallow copy) копированием?
2.0 Middle🔥 151 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Deep Copy vs Shallow Copy — две стратегии клонирования объектов
Это критическое различие в Python, которое приводит к багам, если не понимать. Вопрос: когда копируем вложенные структуры, копируем ли мы содержимое или только ссылки?
Shallow Copy — копируются только ссылки на внутренние объекты
import copy
original = [1, [2, 3], 4]
shallow = copy.copy(original) # Поверхностная копия
# Список скопирован
shallow[0] = 999
print(original[0]) # 1 (не изменился)
# НО внутренний список имеет ТЕ ЖЕ ссылки
shallow[1][0] = 999
print(original[1]) # [999, 3] ← Изменился оригинал!
Визуально:
original → [ ][ →[2, 3]← ][ ]
↓ ↑
shallow → [ ][ →[2, 3]← ][ ]
копия одна и та же внутренняя ссылка!
Deep Copy — копируются все вложенные объекты
import copy
original = [1, [2, 3], 4]
deep = copy.deepcopy(original) # Глубокая копия
# Список скопирован
deep[0] = 999
print(original[0]) # 1
# Внутренний список ТОЖЕ скопирован
deep[1][0] = 999
print(original[1]) # [2, 3] ← Оригинал не изменился!
Визуально:
original → [ ][ →[2, 3]← ][ ]
deep → [ ][ →[2, 3]← ][ ]
разные объекты во всех слоях!
Практические примеры
Shallow Copy — проблемы
# Проблема 1: настройки приложения
default_config = {
"database": {"host": "localhost", "port": 5432},
"redis": {"port": 6379}
}
project_config = default_config.copy() # Shallow copy
# Изменяем
project_config["database"]["host"] = "production.db.com"
# Упс! Изменили оригинал
print(default_config["database"]["host"]) # "production.db.com"
Deep Copy — правильно
import copy
default_config = {
"database": {"host": "localhost", "port": 5432},
"redis": {"port": 6379}
}
project_config = copy.deepcopy(default_config) # Deep copy
project_config["database"]["host"] = "production.db.com"
print(default_config["database"]["host"]) # "localhost" ✓
Как работает shallow copy в Python
original = {"user": {"name": "Alice", "age": 30}}
shallow = original.copy() # или dict(original)
# Это то же самое что:
shallow = {}
for key, value in original.items():
shallow[key] = value # ← Копируем только ссылки!
Когда использовать Shallow Copy
✅ Плоские структуры (нет вложенных объектов)
original = [1, 2, 3, 4, 5]
shallow = original.copy() # Безопасно
original[0] = 999
print(shallow[0]) # 1 (не изменился)
✅ Когда хотим изменять только содержимое верхнего уровня
original_dict = {"a": 1, "b": 2}
copy_dict = original_dict.copy()
copy_dict["a"] = 999 # Никак не влияет на оригинал
Когда использовать Deep Copy
✅ Вложенные структуры
import copy
original = [1, [2, 3], {"key": [4, 5]}]
deep = copy.deepcopy(original)
# Теперь безопасно менять всё
deep[1][0] = 999
deep[2]["key"][0] = 999
print(original) # [1, [2, 3], {'key': [4, 5]}] — не изменился
Копирование объектов класса
class User:
def __init__(self, name, preferences):
self.name = name
self.preferences = preferences # dict
original_user = User("Alice", {"theme": "dark", "lang": "en"})
# ❌ Shallow copy — проблема
shallow_user = copy.copy(original_user)
shallow_user.preferences["theme"] = "light"
print(original_user.preferences["theme"]) # "light" ← Изменился!
# ✅ Deep copy — правильно
deep_user = copy.deepcopy(original_user)
deep_user.preferences["theme"] = "light"
print(original_user.preferences["theme"]) # "dark" ← Не изменился
Производительность
import copy
import time
# Большая вложенная структура
large_data = {"items": [list(range(1000)) for _ in range(100)]}
start = time.time()
for _ in range(10000):
copy.copy(large_data) # Быстро
print(f"Shallow: {time.time() - start}ms")
start = time.time()
for _ in range(10000):
copy.deepcopy(large_data) # Медленнее
print(f"Deep: {time.time() - start}ms")
# Deep copy может быть в 10-100 раз медленнее!
Методы копирования
Shallow Copy:
original = [1, [2, 3]]
# Способ 1: copy.copy()
import copy
shallow = copy.copy(original)
# Способ 2: .copy() метод (для списков, дicts)
shallow = original.copy()
# Способ 3: срез (для списков)
shallow = original[:]
# Способ 4: конструктор
shallow = list(original)
Deep Copy:
import copy
original = [1, [2, 3]]
# Единственный способ
deep = copy.deepcopy(original)
Проблемы с циклическими ссылками
# Shallow copy может зацикливаться
a = [1, 2]
b = [3, a] # b ссылается на a
a.append(b) # a ссылается на b — цикл!
# ❌ Это упадёт
try:
import copy
c = copy.copy(a) # RecursionError
except:
pass
# ✅ Deep copy обрабатывает циклы
d = copy.deepcopy(a) # Работает!
Итог
Shallow Copy:
- Копирует только «корневой» объект
- Внутренние объекты остаются теми же
- Быстро
- ❌ Опасно для вложенных структур
Deep Copy:
- Копирует всё, включая вложенные объекты
- Полная независимость оригинала и копии
- Медленнее
- ✅ Безопасно для сложных структур
Правило:
- Вложенные структуры? →
copy.deepcopy() - Плоские структуры? →
copy.copy()или.copy()