← Назад к вопросам
Глубокое и поверхностное копирование
1.0 Junior🔥 191 комментариев
#Python Core
Условие
Объясните разницу между shallow copy и deep copy в Python.
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a)
c = copy.deepcopy(a)
a[0][0] = 100
print(b) # ?
print(c) # ?
Задача
- Предскажите вывод
- Объясните, когда использовать shallow copy, а когда deep copy
- Как работает оператор присваивания a = b?
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Глубокое и Поверхностное Копирование в Python
Этот вопрос тестирует понимание работы памяти, ссылок и мутируемых объектов в Python.
Предсказание Вывода
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a) # Shallow copy
c = copy.deepcopy(a) # Deep copy
a[0][0] = 100
print(b) # [[100, 2], [3, 4]] — ИЗМЕНИЛСЯ!
print(c) # [[1, 2], [3, 4]] — не изменился
Почему b Изменился?
Shallow copy копирует только верхний уровень структуры. Внутренние объекты остаются теми же самыми:
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a)
print(id(a)) # Разные объекты списков
print(id(b))
print(id(a[0])) # ❌ ОДИНАКОВЫЕ объекты подсписков
print(id(b[0]))
print(a is b) # False — разные списки
print(a[0] is b[0]) # True — один и тот же подсписок!
Диаграмма памяти:
До изменения:
a: [список1] → [[1, 2], [3, 4]]
b: [список2] → [[1, 2], [3, 4]] (копия контейнера, но NOT содержимого)
Оба указывают на одни и те же подсписки [1, 2] и [3, 4]
После a[0][0] = 100:
a[0]: [100, 2] ← изменяется объект на адресе 0x1000
b[0]: [100, 2] ← b всё ещё указывает на тот же адрес 0x1000!
Deep Copy
Deep copy создаёт полную копию со всеми вложенными объектами:
import copy
a = [[1, 2], [3, 4]]
c = copy.deepcopy(a)
print(id(a)) # Разные
print(id(c))
print(id(a[0])) # Разные подсписки
print(id(c[0]))
print(a is c) # False
print(a[0] is c[0]) # False — разные подсписки
a[0][0] = 100
print(a) # [[100, 2], [3, 4]]
print(c) # [[1, 2], [3, 4]] — не изменился
Визуализация
import copy
original = {'user': {'name': 'Alice', 'age': 30}}
# Присваивание (alias)
alias = original
print(alias is original) # True — один объект
# Shallow copy
shallow = copy.copy(original)
print(shallow is original) # False — разные словари
print(shallow['user'] is original['user']) # True — один подсловарь!
# Deep copy
deep = copy.deepcopy(original)
print(deep is original) # False
print(deep['user'] is original['user']) # False — разные подсловари
# Изменение
original['user']['name'] = 'Bob'
print(alias['user']['name']) # Bob (alias указывает на original)
print(shallow['user']['name']) # Bob (shallow указывает на тот же подсловарь)
print(deep['user']['name']) # Alice (deep — независимая копия)
Оператор Присваивания a = b
Присваивание — это не копирование, а создание ссылки (alias):
a = [1, 2, 3]
b = a # b указывает на тот же объект
print(a is b) # True — один объект в памяти
print(id(a) == id(b)) # True
a.append(4)
print(b) # [1, 2, 3, 4] — изменение видно через обе переменные
Три уровня копирования:
import copy
original = [[1, 2], [3, 4]]
# 1. Присваивание (alias) — копирование ссылки
alias = original
# Результат: alias и original указывают на один объект
# 2. Shallow copy — копирование контейнера
shallow = copy.copy(original)
# Результат: новый список, но с ссылками на те же подсписки
# 3. Deep copy — полное копирование
deep = copy.deepcopy(original)
# Результат: новый список со своими подсписками
print(original is alias) # True
print(original is shallow) # False
print(original is deep) # False
print(original[0] is shallow[0]) # True
print(original[0] is deep[0]) # False
Когда Использовать?
Присваивание a = b:
- Хочешь просто ещё одно имя для того же объекта
- Передача объекта в функцию
- Экономия памяти
def process(data):
data[0] = 100 # Изменяет оригинальный список
my_list = [1, 2, 3]
process(my_list) # my_list теперь [100, 2, 3]
Shallow copy copy.copy():
- Нужна копия контейнера, но содержимое может измениться
- Работа с простыми типами (числа, строки)
- Оптимизация памяти
import copy
list1 = [1, 2, 3]
list2 = copy.copy(list1)
list2.append(4)
print(list1) # [1, 2, 3] — не изменился (список был изменён)
Deep copy copy.deepcopy():
- Нужна полностью независимая копия со всеми вложенными объектами
- Работа со сложными структурами (списки списков, словари с вложенными словарями)
- Когда вложенные объекты могут измениться
import copy
original = {'users': [{'name': 'Alice'}, {'name': 'Bob'}]}
copy_data = copy.deepcopy(original)
copy_data['users'][0]['name'] = 'Charlie'
print(original['users'][0]['name']) # Alice — не изменился
Практические Примеры
import copy
# Пример 1: Shallow copy для простого списка
nums = [1, 2, 3]
copied = copy.copy(nums)
copied[0] = 99
print(nums) # [1, 2, 3] — не изменился
# Пример 2: Deep copy для вложенных структур
config = {'db': {'host': 'localhost', 'port': 5432}}
config_copy = copy.deepcopy(config)
config_copy['db']['host'] = 'remote'
print(config['db']['host']) # localhost — не изменился
# Пример 3: Пользовательские объекты
class Person:
def __init__(self, name, friends):
self.name = name
self.friends = friends # список
alice = Person('Alice', ['Bob', 'Charlie'])
alice_copy = copy.copy(alice)
alice_copy.friends.append('David')
print(alice.friends) # ['Bob', 'Charlie', 'David'] — shallow!
alice_deep = copy.deepcopy(alice)
alice_deep.friends.append('Eve')
print(alice.friends) # Не изменился — deep copy
Рекомендация
Для собеседования:
- Вывод: b изменился, c нет
- Объяснение: shallow copy копирует только контейнер, а не содержимое
- Присваивание: создаёт ссылку, не копирует
- Практика: используй deep copy для сложных структур, shallow для простых
Это демонстрирует глубокое понимание того, как Python управляет памятью и ссылками.