Ответ
deepcopy() из модуля copy используется для создания полной, рекурсивной копии объекта, включая все объекты, на которые он ссылается, объекты внутри них и так далее. Это гарантирует, что между оригиналом и копией не останется общих ссылок на изменяемые (mutable) объекты.
Принцип работы:
- Функция
deepcopy(x)создает новый объект того же типа, что иx. - Затем она рекурсивно обходит все элементы/атрибуты объекта
x. - Для каждого найденного элемента:
- Если элемент является примитивом (число, строка) или неизменяемым объектом, он просто присваивается в копию (так как его изменение невозможно, общая ссылка безопасна).
- Если элемент является изменяемым объектом (список, словарь, экземпляр класса), для него рекурсивно вызывается
deepcopy(), и в копию помещается уже его глубокая копия.
- Для корректной обработки циклических ссылок
deepcopy()использует словарьmemo, который хранит соответствиеid(оригинала) -> копия, чтобы не уйти в бесконечную рекурсию.
Типичные сценарии использования:
- Копирование сложных структур данных:
import copy
config = { 'model_params': {'learning_rate': 0.01, 'layers': [64, 32]}, 'data_paths': ['/train.csv', '/test.csv'] }
Создаем экспериментальную копию конфига
new_config = copy.deepcopy(config) new_config['model_params']['layers'].append(16) # Меняем только копию print(config['model_params']['layers']) # [64, 32] - оригинал не тронут
2. **Работа с изменяемыми аргументами по умолчанию в функциях (избегание известной проблемы):**
```python
def process_data(data, cache=[]): # ОПАСНО: изменяемый аргумент по умолчанию!
cache.append(data)
return cache
# Безопасная версия с deepcopy
from copy import deepcopy
def process_data_safe(data, cache=None):
if cache is None:
cache = []
# Создаем копию кэша, чтобы не менять внешний объект, если он был передан
current_cache = deepcopy(cache)
current_cache.append(data)
return current_cache
- Создание независимых копий объектов в симуляциях или играх:
class Unit: def __init__(self, health, position): self.health = health self.position = list(position) # Изменяемый список
original_unit = Unit(100, [0, 0]) cloned_unit = copy.deepcopy(original_unit) cloned_unit.position[0] = 5 # Движем клон, оригинал остается на месте [0, 0]
**Производительность:** `deepcopy()` может быть медленной операцией для больших и глубоких структур. Всегда оценивайте необходимость её использования. Для простых случаев часто достаточно поверхностного копирования (`copy()`).