Что такое глубокое копирование в Python?

Ответ

Глубокое копирование (deep copy) — это создание нового составного объекта (например, списка списков, словаря со вложенными словарями) и рекурсивное копирование всех объектов, найденных в исходном, делая копию полностью независимой от оригинала. Изменения во вложенных объектах оригинала не затронут копию, и наоборот.

Почему это важно в тестировании на Python? Часто нужно подготовить тестовые данные (фикстуры), модифицировать их в тесте, но при этом сохранить исходное состояние для других тестов или для сравнения "до/после". Поверхностное копирование (copy.copy() или list()) здесь подведет.

Пример проблемы и решения:

import copy

# Исходные тестовые данные (сложная структура)
test_config_original = {
    'server': {'host': 'localhost', 'port': 8080},
    'users': [{'id': 1, 'role': 'admin'}, {'id': 2, 'role': 'tester'}]
}

# ПОВЕРХНОСТНОЕ копирование (опасно!)
test_config_shallow = copy.copy(test_config_original)
# ИЛИ test_config_shallow = dict(test_config_original)

# ГЛУБОКОЕ копирование (правильно для независимой копии)
test_config_deep = copy.deepcopy(test_config_original)

# Модифицируем вложенный объект в "копии"
test_config_shallow['server']['port'] = 9999  # Меняет ОРИГИНАЛ!
test_config_deep['users'][0]['role'] = 'superuser'  # Не меняет оригинал

print("Original:", test_config_original['server']['port'])  # 9999 (!)
print("Original user role:", test_config_original['users'][0]['role'])  # 'admin' (ok)

Когда использовать deepcopy в автотестах:

  • Подготовка изолированных фикстур для параметризованных тестов.
  • Эмуляция состояния данных "до выполнения операции" для последующего сравнения.
  • Создание модифицированных конфигов для тестирования разных сценариев на основе базового.

Минус: deepcopy работает медленнее и потребляет больше памяти, чем поверхностное копирование, поэтому для простых, одноуровневых структур оно избыточно.

Ответ 18+ 🔞

Бля, слушай, вот есть такая тема — глубокое копирование. Это когда ты не просто скопировал верхнюю бумажку, а залез во все папки, конверты и даже в записки на салфетках, и всё это переснял заново. Получается полностью независимый дубликат, как близнец. Изменяешь что-то в копии — оригинал нихуя не страдает, и наоборот.

А нахуя это в тестах нужно, спросишь ты? А затем, ёпта, что тебе часто надо взять эталонные данные, поебаться с ними в тесте, но при этом оставить оригинал в покое, чтобы другие тесты не охуели от твоих правок. Если сделаешь поверхностное копирование (тот же copy.copy()), то это пиздец, а не копия — ты залезешь внутрь вложенного словаря, а меняется всё везде.

Смотри, как это выглядит на практике:

import copy

# Допустим, у тебя сложная конфигурация для тестов
test_config_original = {
    'server': {'host': 'localhost', 'port': 8080},
    'users': [{'id': 1, 'role': 'admin'}, {'id': 2, 'role': 'tester'}]
}

# ПОВЕРХНОСТНОЕ копирование (это ловушка, ебать!)
test_config_shallow = copy.copy(test_config_original)
# Или так: test_config_shallow = dict(test_config_original) — хуйня та же.

# ГЛУБОКОЕ копирование (вот это уже дело, ядрёна вошь!)
test_config_deep = copy.deepcopy(test_config_original)

# Теперь накосячим в "копиях"
test_config_shallow['server']['port'] = 9999  # Опа-на! Это меняет и ОРИГИНАЛ, сука!
test_config_deep['users'][0]['role'] = 'superuser'  # А вот это уже нет, оригинал чист.

print("Original port:", test_config_original['server']['port'])  # 9999 (ёбаный насос!)
print("Original user role:", test_config_original['users'][0]['role'])  # 'admin' (вот и хорошо)

Так когда же тыкать deepcopy в своих автотестах?

  • Когда готовишь изолированные фикстуры для кучи параметризованных тестов, чтобы они друг другу не нагадили.
  • Когда надо зафиксировать состояние данных "до того как", чтобы потом сравнить с результатом.
  • Когда на основе одного базового конфига нужно нагенерить кучу разных сценариев для проверки.

Но есть и подвох: deepcopy — не самая шустрая операция, жрёт память и время, как не в себя. Поэтому если структура простая, одноуровневая, то это овердохуища, не трать ресурсы. Используй с умом.