Почему список меняется неожиданно, хотя я его не трогал? (ссылки в Python)
Скопировал список b = a, потом изменил b, а изменился и a! Я же работал только с копией. Почему второй список меняется вместе с первым и как сделать настоящую копию?
2 ответа
Дело в том, что b = a не создаёт копию списка — это просто второе имя для того же самого объекта в памяти. Списки в Python изменяемые, и обе переменные ссылаются на один список, поэтому меняя один, вы меняете «оба».
a = [1, 2, 3]
b = a # b и a — это один и тот же список
b.append(4)
print(a) # [1, 2, 3, 4] — изменился и a!
Как сделать настоящую (поверхностную) копию:
b = a.copy() # или b = a[:] или b = list(a)
b.append(4)
print(a) # [1, 2, 3] — a не тронут
Важный нюанс: copy() копирует только верхний уровень. Если внутри списка лежат вложенные списки/словари, они всё ещё общие:
a = [[1, 2], [3, 4]]
b = a.copy()
b[0].append(99)
print(a) # [[1, 2, 99], [3, 4]] — вложенный список общий!
Для полностью независимой копии используйте глубокое копирование:
import copy
b = copy.deepcopy(a)
Правило: присваивание (=) делает алиас (второе имя), а не копию. Для копии нужен .copy(), срез [:] или deepcopy для вложенных структур.
То же самое работает и с функциями: если передать список в функцию и изменить его там (через append, [i] = ...), изменится оригинал, потому что внутрь попадает та же ссылка. Чтобы не портить исходный список, делайте копию в начале функции: data = data.copy().