Вопрос 12 из 16
Основы Python
Расскажи особенности копирования изменяемых объектов
Показать ответ
Короткий ответ
- Поверхностное копирование (copy()) создает новый объект, но вложенные объекты остаются ссылками
- Глубокое копирование (deepcopy()) рекурсивно копирует все вложенные объекты
Развернутый ответ
Копирование изменяемых объектов в Python требует особого внимания, так как простое присваивание создает лишь новую ссылку на тот же объект. Вот основные способы и их особенности:
1. Поверхностное копирование (shallow copy)
Создает новый объект, но вкладывает в него ссылки на те же вложенные объекты.
Методы:
import copy
# Для списков
original = [1, [2, 3], 4]
shallow_copy = original.copy() # или copy.copy(original) или original[:]
# Для словарей
dict_original = {'a': [1, 2]}
dict_copy = dict_original.copy()
Особенности:
- Изменения вложенных mutable-объектов затрагивают оригинал
- Быстрее глубокого копирования
- Достаточно для одноуровневых структур
original[1].append(5)
print(shallow_copy) # [1, [2, 3, 5], 4] - вложенный список изменился!
2. Глубокое копирование (deep copy)
Рекурсивно создает новые копии всех вложенных объектов.
import copy
original = [1, [2, 3], 4]
deep_copy = copy.deepcopy(original)
original[1].append(5)
print(deep_copy) # [1, [2, 3], 4] - копия осталась неизменной
Особенности:
- Полная изоляция от изменений в оригинале
- Затратно по памяти и времени для сложных структур
- Может вызвать проблемы с циклическими ссылками
3. Особые случаи
Копирование сложных структур
data = {
'items': [1, 2, {'key': 'value'}],
'config': {'settings': [True, False]}
}
data_copy = copy.deepcopy(data)
Копирование пользовательских классов
class MyClass:
def __init__(self, x):
self.x = x
obj = MyClass([1, 2, 3])
obj_copy = copy.deepcopy(obj)
4. Различия методов копирования
Метод | Уровень | Изменения в оригинала | Производительность |
---|---|---|---|
Присваивание (=) | Нет копирования | Всегда видны | Мгновенно |
.copy() / copy.copy() | Поверхностное | Видны для вложенных объектов | Быстро |
copy.deepcopy() | Глубокое | Не видны | Медленно |
5. Рекомендации
- Используйте глубокое копирование для структур с вложенными изменяемыми объектами
- Для простых списков/словарей достаточно shallow copy
- Избегайте глубокого копирования для объектов с циклическими ссылками
- Для пользовательских классов можно определить
__copy__
и__deepcopy__
class MyClass:
def __init__(self, x):
self.x = x
def __copy__(self):
return MyClass(self.x.copy())
def __deepcopy__(self, memo):
return MyClass(copy.deepcopy(self.x, memo))
Правильное копирование особенно важно при работе с многопоточными приложениями и изменяемыми аргументами функций.