Как сделать настоящую копию списка в Python, а не ссылку?
Сделал b = a, изменил b, а у меня изменился и a! Похоже, это одна и та же штука. Как сделать независимую копию списка, чтобы правки в одной переменной не трогали другую?
2 ответа
b = a не копирует список — обе переменные указывают на один и тот же объект в памяти. Поэтому правка через b видна и в a.
Чтобы сделать независимую (поверхностную) копию, есть несколько способов:
a = [1, 2, 3]
b = a[:] # срез всего списка
c = a.copy() # метод copy
d = list(a) # через конструктор
Все три создают новый список. Теперь b.append(4) не тронет a.
Проверить, один ли это объект, можно оператором is:
b is a # False — разные объекты
Важный нюанс — это поверхностная копия. Если внутри списка лежат вложенные списки или словари, копируются только ссылки на них, и вложенные объекты остаются общими:
a = [[1, 2], [3, 4]]
b = a.copy()
b[0].append(99) # изменит и a[0]!
Для полностью независимой копии вложенных структур нужен deepcopy:
import copy
b = copy.deepcopy(a)
Правило: плоский список (числа, строки) — хватит a[:] или .copy(); список списков/словарей — deepcopy.
То же касается словарей: d2 = d1 это ссылка, а d2 = d1.copy() это копия.
Быстрый способ запомнить: присваивание = в Python никогда не копирует объекты, оно лишь привязывает новое имя к тому же объекту. Копию нужно создавать явно. Для списков это [:], .copy() или list(); для глубоких структур — copy.deepcopy(). Если переменная неизменяема (число, строка, кортеж), про копирование можно не думать — её всё равно нельзя поменять на месте.