Какие способы копирования объектов существуют в Python
Что проверяют
Понимаете ли вы, что переменная в Python это ссылка, и что присваивание копией не является. Вопрос базовый, но по ответу видно, наступали ли вы на общий вложенный список у двух «разных» объектов. Дальше просят рассказать, что произойдёт с пользовательским классом и как управлять копированием вручную.
Как отвечать
Разложите на три уровня.
- присваивание:
b = aсоздаёт вторую ссылку на тот же объект,a is bистинно, изменения видны с обеих сторон; - поверхностная копия:
copy.copy(a),a[:],list(a),dict(d),{**d},d.copy(). Новый контейнер, но элементы внутри те же объекты: меняете вложенный список и видите изменение в обоих; - глубокая копия:
copy.deepcopy(a)рекурсивно копирует всё дерево и ведёт словарьmemo, поэтому корректно переживает циклические ссылки и сохраняет разделение. Если один объект встречался в структуре дважды, в копии он тоже будет один.
Добавьте детали, которые отличают уверенный ответ. Неизменяемые объекты не копируются: copy.copy на кортеже, строке или числе вернёт тот же объект, и это нормально. Для своих классов работают протоколы __copy__ и __deepcopy__, а без них модуль опирается на __reduce_ex__ и создаёт экземпляр без вызова __init__, перенося __dict__. Для датаклассов есть dataclasses.replace, а с Python 3.13 общий copy.replace() через протокол __replace__, он же работает для datetime и именованных кортежей.
Скажите про цену: deepcopy медленный, на больших структурах его заменяют конструктором. И про то, что копировать нельзя: файловые объекты, соединения с базой, блокировки, сокеты.
Где спотыкаются
Считают срез a[:] глубокой копией. Для плоского списка чисел разницы не видно, для списка списков баг всплывает через неделю.
Забывают про изменяемое значение по умолчанию: def f(x=[]). Список создаётся один раз при определении функции и живёт между вызовами, правильный приём это None плюс создание внутри.
Обещают, что deepcopy зациклится на кольцевых ссылках. Наоборот, memo это ровно тот механизм, который защищает от бесконечной рекурсии. А вот собственный __deepcopy__, который не передаёт memo дальше, действительно зациклится.