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

Как использовать copy в Python?

2.0 Middle🔥 171 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как использовать copy в Python

Модуль copy в Python предоставляет функции для создания копий объектов. Это критически важно для понимания, так как многие разработчики путают поверхностное и глубокое копирование, что приводит к багам. Разберу детально.

Основная проблема: ссылки vs копии

# ❌ Это не копирование, а присваивание ссылки
original = [1, 2, [3, 4]]
shallow = original  # Обе переменные указывают на ОДИН объект!

shallow[0] = 999
print(original)  # [999, 2, [3, 4]] — оригинал изменился!

1. Shallow Copy (Поверхностное копирование)

Копирует сам объект, но не копирует вложенные объекты:

import copy

original = [1, 2, [3, 4]]
shallow = copy.copy(original)

# Изменение элемента первого уровня
shallow[0] = 999
print(original)  # [1, 2, [3, 4]] — оригинал не изменился ✓

# Но вложенный список общий!
shallow[2].append(5)
print(original)  # [1, 2, [3, 4, 5]] — оригинал изменился ✗

2. Deep Copy (Глубокое копирование)

Рекурсивно копирует всё, включая вложенные объекты:

import copy

original = [1, 2, [3, 4]]
deep = copy.deepcopy(original)

# Изменение любого уровня не влияет на оригинал
deep[2].append(5)
print(original)  # [1, 2, [3, 4]] — оригинал не изменился ✓
print(deep)      # [1, 2, [3, 4, 5]]

3. Практические примеры

С словарями:

original_dict = {
    "name": "Alice",
    "scores": [10, 20, 30]
}

# Shallow copy
shallow = copy.copy(original_dict)
shallow["scores"].append(40)
print(original_dict)  # scores изменился — [10, 20, 30, 40]

# Deep copy
deep = copy.deepcopy(original_dict)
deep["scores"].append(50)
print(original_dict)  # scores не изменился — [10, 20, 30, 40]

С пользовательскими классами:

class User:
    def __init__(self, name, skills):
        self.name = name
        self.skills = skills

user1 = User("Bob", ["Python", "SQL"])

# Shallow copy
user2 = copy.copy(user1)
user2.skills.append("Django")  # Изменяется список user1!

# Deep copy
user3 = copy.deepcopy(user1)
user3.skills.append("FastAPI")  # user1 не затронут ✓

4. Альтернативные способы копирования

Для списков:

original = [1, 2, 3]

# Способ 1: срез
copy1 = original[:]  # shallow copy

# Способ 2: конструктор
copy2 = list(original)  # shallow copy

# Способ 3: copy.copy()
copy3 = copy.copy(original)  # shallow copy

Для словарей:

original = {"a": 1, "b": [2, 3]}

# Способ 1: распаковка
copy1 = {**original}  # shallow copy

# Способ 2: конструктор
copy2 = dict(original)  # shallow copy

# Способ 3: copy.copy()
copy3 = copy.copy(original)  # shallow copy

5. Кастомное копирование в классах

Если класс имеет сложную логику, переопредели методы копирования:

class DataModel:
    def __init__(self, data):
        self.data = data
        self._cache = {}  # Не копируем кэш
    
    def __copy__(self):
        new_obj = self.__class__(self.data[:])
        return new_obj
    
    def __deepcopy__(self, memo):
        new_obj = self.__class__(copy.deepcopy(self.data, memo))
        return new_obj

6. Когда что использовать

СценарийВыбор
Нужна полная независимость копииdeepcopy
Известно, что вложенные объекты не меняютсяcopy
Работаешь с простыми списками/словарямиlist() / dict()
Нужна максимальная производительностьссылка (осторожно!)

Производительность

import time
import copy

data = [[i] * 1000 for i in range(1000)]

start = time.time()
shallow = copy.copy(data)
print(f"Shallow: {time.time() - start:.6f}s")

start = time.time()
deep = copy.deepcopy(data)
print(f"Deep: {time.time() - start:.6f}s")

# Deep работает медленнее, но гарантирует полную независимость

Вывод

Всегда используй deepcopy если не уверен, нужен copy если явно нужна поверхностная копия. Ошибка в выборе приводит к трудноуловимым багам в production.