← Назад к вопросам

В чем разница между глубоким (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()
В чем разница между глубоким (deep copy) и поверхностным (shallow copy) копированием? | PrepBro