Ответ
Глубокое копирование (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 — не самая шустрая операция, жрёт память и время, как не в себя. Поэтому если структура простая, одноуровневая, то это овердохуища, не трать ресурсы. Используй с умом.