Срез списка в Python создает поверхностную или глубокую копию?

Ответ

Срез списка в Python (например, new_list = old_list[:]) создает поверхностную (shallow) копию.

Это означает, что создается новый объект-список, но он заполняется ссылками на те же самые объекты, которые содержались в оригинальном списке.

  • Для неизменяемых объектов (числа, строки) это не имеет значения, так как их нельзя изменить.
  • Для изменяемых объектов (списки, словари) изменение вложенного объекта в одной копии отразится и в другой, поскольку обе копии ссылаются на один и тот же вложенный объект.

Пример:

import copy

original_list = [[1, 2], [3, 4]]

# 1. Поверхностная копия (shallow copy) с помощью среза
shallow_copy = original_list[:]

# Изменяем вложенный список через поверхностную копию
shallow_copy[0][0] = 999

# Изменение отразилось и в оригинале, т.к. вложенный список - общий объект
print(f"Оригинал после shallow copy: {original_list}") # [[999, 2], [3, 4]]
print(f"Shallow copy:              {shallow_copy}")    # [[999, 2], [3, 4]]

# 2. Глубокая копия (deep copy) для сравнения
deep_copy = copy.deepcopy(original_list)

# Изменяем вложенный список через глубокую копию
deep_copy[0][1] = 777

# Изменение НЕ отразилось в оригинале, т.к. все объекты рекурсивно скопированы
print(f"Оригинал после deep copy:   {original_list}") # [[999, 2], [3, 4]]
print(f"Deep copy:                 {deep_copy}")    # [[999, 777], [3, 4]]

Вывод: Используйте срезы для быстрого копирования списков с неизменяемыми элементами. Если список содержит вложенные изменяемые структуры, для полной независимости копий используйте copy.deepcopy().

Ответ 18+ 🔞

Давай разберём эту дичь, которая в Питоне называется «копирование списков». Ситуация, в общем, пиздец как простая, но люди постоянно об неё обжигаются, как дураки о горячий чайник.

Смотри, есть у тебя список. Допустим, old_list. Ты такой: «О, ща сделаю копию, чтобы оригинал не трогать!» И пишешь new_list = old_list[:]. И думаешь, что ты молодец, блядь, и всё чики-пуки.

А вот нихуя! Это, сука, поверхностная копия (shallow copy). Что это значит на языке нормальных людей? Это значит, что ты создал новую коробку (новый список), но положил в неё не сами вещи, а бумажки с адресами, где эти вещи лежат.

  • Если в коробке лежат кирпичи (числа, строки) — похуй. Кирпич не изменишь. Сделал копию бумажки «кирпич №1» — и хрен с ним, он так и останется кирпичом.
  • А вот если в коробке лежат коробки поменьше (списки, словари) — вот тут начинается пиздец. Потому что обе твои бумажки (в оригинале и в копии) ведут к одной и той же маленькой коробке. Полез ты в копию, достал эту маленькую коробку и нахуярил туда мармеладок. А потом смотришь в оригинал — а там тоже мармеладки! Потому что коробка-то одна, блядь!

Пример, чтобы мозг не взорвался:

import copy

# Есть список, а в нём вложенные списки. Как матрёшка, епта.
original_list = [[1, 2], [3, 4]]

# 1. Делаем «умную» копию срезом (поверхностную)
shallow_copy = original_list[:]

# Лезем в копию и меняем что-то ВНУТРИ вложенного списка
shallow_copy[0][0] = 999  # Меняем не shallow_copy, а то, что внутри него!

# Смотрим, что получилось... Охуеть!
print(f"Оригинал после shallow copy: {original_list}") # [[999, 2], [3, 4]]
print(f"Shallow copy:              {shallow_copy}")    # [[999, 2], [3, 4]]
# Видишь? Оба списка показывают одно и то же дерьмо. Потому что внутренний список [[1,2]] — он один на двоих, как последняя шмотка в семье.

# 2. Теперь делаем копию по-взрослому, глубокую (deep copy)
deep_copy = copy.deepcopy(original_list)

# Опять хуярим изменение внутри копии
deep_copy[0][1] = 777

# И смотрим — магия, блядь!
print(f"Оригинал после deep copy:   {original_list}") # [[999, 2], [3, 4]]
print(f"Deep copy:                 {deep_copy}")    # [[999, 777], [3, 4]]
# Оригинал не тронут! Потому что `deepcopy` прошлась как терминатор и скопировала ВСЁ рекурсивно, до последней пылинки. Создала новые коробки для всех внутренних коробок.

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