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

При использовании copy копируются ли все вложенности

1.8 Middle🔥 131 комментариев
#Python Core

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

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

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

# При использовании copy копируются ли все вложенности?

Нет, обычная copy() (shallow copy) копирует только первый уровень. Вложенные объекты остаются общими ссылками. Для копирования всех вложенностей нужна deepcopy().

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

Скопированы только ссылки на вложенные объекты, сами объекты общие.

import copy

# Пример со списком списков
original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
shallow = copy.copy(original)

print(f"original is shallow: {original is shallow}")  # False (разные списки)
print(f"original[0] is shallow[0]: {original[0] is shallow[0]}")  # True! (одинаковые подсписки)

# Изменение вложенного списка влияет на оба
shallow[0][0] = 999
print(f"original: {original}")    # [[999, 2, 3], [4, 5, 6], [7, 8, 9]]
print(f"shallow: {shallow}")      # [[999, 2, 3], [4, 5, 6], [7, 8, 9]]

# Но замена самого подсписка не влияет
shallow[0] = [100, 200, 300]
print(f"original: {original}")    # [[999, 2, 3], [4, 5, 6], [7, 8, 9]] — не изменился!
print(f"shallow: {shallow}")      # [[100, 200, 300], [4, 5, 6], [7, 8, 9]]

2. Deep Copy (глубокая копия)

Рекурсивно копируются все вложенные объекты.

import copy

original = [[1, 2, 3], [4, 5, 6], {'name': 'Alice', 'scores': [90, 85]}]
deep = copy.deepcopy(original)

print(f"original is deep: {original is deep}")              # False
print(f"original[0] is deep[0]: {original[0] is deep[0]}")  # False (разные подсписки!)
print(f"original[2] is deep[2]: {original[2] is deep[2]}")  # False (разные словари!)
print(f"original[2]['scores'] is deep[2]['scores']: {original[2]['scores'] is deep[2]['scores']}")  # False

# Изменения в deep не влияют на original
deep[0][0] = 999
deep[2]['scores'][0] = 50

print(f"original: {original}")  # [[1, 2, 3], [4, 5, 6], {'name': 'Alice', 'scores': [90, 85]}]
print(f"deep: {deep}")          # [[999, 2, 3], [4, 5, 6], {'name': 'Alice', 'scores': [50, 85]}]

3. Сравнение shallow vs deep

import copy

class Student:
    def __init__(self, name, grades):
        self.name = name
        self.grades = grades  # список оценок
    
    def __repr__(self):
        return f"Student(name={self.name}, grades={self.grades})"

# Исходный объект
original = Student("Alice", [90, 85, 95])

# Shallow copy
shallow = copy.copy(original)
print(f"original is shallow: {original is shallow}")                    # False (разные объекты Student)
print(f"original.grades is shallow.grades: {original.grades is shallow.grades}")  # True! (одинаковые списки оценок)

# Deep copy
deep = copy.deepcopy(original)
print(f"original is deep: {original is deep}")                         # False
print(f"original.grades is deep.grades: {original.grades is deep.grades}")  # False (разные списки оценок)

# Изменение в shallow
shallow.grades[0] = 50  # Меняем оценку в shallow
print(f"original.grades: {original.grades}")  # [50, 85, 95] — изменилась!
print(f"shallow.grades: {shallow.grades}")    # [50, 85, 95]

# Изменение в deep
deep.grades[0] = 100
print(f"original.grades: {original.grades}")  # [50, 85, 95] — не изменилась
print(f"deep.grades: {deep.grades}")          # [100, 85, 95]

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

❌ Неправильно: shallow copy для конфигурации

import copy

# Конфигурация с вложенными параметрами
base_config = {
    'database': {'host': 'localhost', 'port': 5432},
    'cache': {'ttl': 3600, 'backends': ['redis', 'memcached']},
    'features': {'auth': True, 'api': True}
}

# Создаём копию для другого окружения
dev_config = copy.copy(base_config)  # ОШИБКА!

# Меняем host для dev
dev_config['database']['host'] = '127.0.0.1'

print(f"base_config['database']['host']: {base_config['database']['host']}")  # '127.0.0.1' — испортили базовую конфиг!
print(f"dev_config['database']['host']: {dev_config['database']['host']}")    # '127.0.0.1'

✅ Правильно: deep copy для конфигурации

import copy

base_config = {
    'database': {'host': 'localhost', 'port': 5432},
    'cache': {'ttl': 3600, 'backends': ['redis', 'memcached']},
    'features': {'auth': True, 'api': True}
}

# Глубокая копия для другого окружения
dev_config = copy.deepcopy(base_config)  # Правильно!

# Меняем только в dev
dev_config['database']['host'] = '127.0.0.1'
dev_config['cache']['ttl'] = 300

print(f"base_config['database']['host']: {base_config['database']['host']}")  # 'localhost' — не испортилась
print(f"base_config['cache']['ttl']: {base_config['cache']['ttl']}")          # 3600 — не испортилась
print(f"dev_config['database']['host']: {dev_config['database']['host']}")    # '127.0.0.1'
print(f"dev_config['cache']['ttl']: {dev_config['cache']['ttl']}")            # 300

5. Копирование словарей и списков

# Для словаря
original_dict = {'a': 1, 'b': [1, 2, 3]}
shallow_dict = original_dict.copy()        # Shallow copy
deep_dict = copy.deepcopy(original_dict)   # Deep copy

# Для списка
original_list = [1, 2, [3, 4, 5]]
shallow_list = original_list.copy()        # Shallow copy
shallow_list2 = original_list[:]           # Также shallow copy
deep_list = copy.deepcopy(original_list)   # Deep copy

original_list[2][0] = 999
print(f"original_list: {original_list}")      # [1, 2, [999, 4, 5]]
print(f"shallow_list: {shallow_list}")        # [1, 2, [999, 4, 5]] — испортилась!
print(f"shallow_list2: {shallow_list2}")      # [1, 2, [999, 4, 5]] — испортилась!
print(f"deep_list: {deep_list}")              # [1, 2, [3, 4, 5]] — осталась целой

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

import copy
import time

# Большая структура с вложенностями
big_data = [{'id': i, 'values': list(range(100))} for i in range(10000)]

# Shallow copy быстрее
start = time.time()
for _ in range(1000):
    copy.copy(big_data)
shallow_time = time.time() - start

# Deep copy медленнее
start = time.time()
for _ in range(1000):
    copy.deepcopy(big_data)
deep_time = time.time() - start

print(f"Shallow copy: {shallow_time:.4f} сек")
print(f"Deep copy: {deep_time:.4f} сек")
print(f"Deep copy медленнее в {deep_time / shallow_time:.1f}x раз")

Таблица сравнения

ОперацияShallow CopyDeep Copy
Копирует весь объектДа (только 1-й уровень)Да (рекурсивно все уровни)
Копирует вложенные объектыНет (общие ссылки)Да (новые копии)
СкоростьБыстроМедленно
ПамятьМеньшеБольше
БезопасностьНизкая (изменения влияют)Высокая (независимые копии)
ИспользуетсяРедко в productionЧасто для безопасности данных

Когда использовать?

import copy

# Используй shallow copy только когда:
# 1. Уверен, что не будешь менять вложенные объекты
# 2. Нужна максимальная производительность

users_refs = original_users.copy()  # OK если только читаешь

# Используй deep copy когда:
# 1. Нужны полностью независимые копии
# 2. Мутируешь вложенные данные
# 3. Работаешь с конфигурациями, кэшами

safe_config = copy.deepcopy(original_config)  # Правильно!

Вывод

copy.copy() копирует только первый уровень. Вложенные объекты остаются общими ссылками. Используй copy.deepcopy() для полного копирования всех вложенностей, если не хочешь неожиданных побочных эффектов при изменении данных.