Как очистить список в Python. Почему очистка списка удаляет его копии в других переменных
Почему очистка списка в Python приводит к удалению его копий в других переменных
Очистку списка в Python можно выполнить несколькими способами, некоторые из которых могут привести к неожиданным результатам, если вы не знаете различий и того, что происходит под капотом.
Давайте посмотрим на очень простой скрипт, который не делает ничего значимого, но продемонстрирует, что я имею в виду:
temp_list = list()
dict_config = dict()
for l in ['a', 'b', 'c']:
for n in range(1,4):
temp_list.append(l + str(n))
dict_config[l] = temp_list
temp_list.clear()
print(dict_config)
Этот скрипт создает список и словарь. Затем он выполняет два цикла, один из которых является вложенным. Вложенный цикл заполняет список, а затем добавляет этот список в словарь (используя одну из итераций в качестве ключа). Временный список очищается, чтобы его можно было использовать снова и снова в одном и том же цикле, но с разными данными.
Какой результат вы ожидаете?
По замыслу автора скрипта, в результате должен получиться словарь следующего содержания:
{'a': ['a1', 'a2', 'a3'], 'b': ['b1', 'b2', 'b3'], 'c': ['c1', 'c2', 'c3']}
Но что же на самом деле получается при выполнении скрипта?
Полученный результат:
{'a': [], 'b': [], 'c': []}
То есть словарь действительно создан, ключи у него есть, но значения (которые должны были быть временными списками) пусты.
Этот пример представляет собой адаптацию фрагмента скрипта с более значимой функцией. Но в любом случае списки можно использовать как временное хранилище динамических данных, поэтому нам нужно разобраться, в чем именно проблема.
Логической ошибки в скрипте нет — проблема в способе очистки списка.
Как очистить список в Python
Списки в Python можно очищать несколькими способами, что приводит к 2 возможным вариантам:
1) Один из методов работает «на месте», то есть очищает те ячейки памяти, в которых хранится содержимое списка). Даже после того, как список сохранен в словаре как значение, словарь сохраняет не дубликат информации из списка, а ссылку на область памяти, где расположен список. Это приводит к тому, что если список очищается, то он очищается и в словаре, так как это не дублирующиеся данные, а всего лишь ссылка на область памяти, в которой теперь ничего нет.
2) Второй метод очистки просто создает новый объект списка и присваивает его одноименной переменной (той же переменной). При использовании этого метода очистки список, ранее сохраненный в словаре, не затрагивается.
Рассмотрим тот же скрипт, в котором строка
temp_list.clear()
заменяется строкой:
temp_list = []
То есть в качестве метода очистки выбирается присвоение нового пустого значения.
temp_list = list()
dict_config = dict()
for l in ['a', 'b', 'c']:
for n in range(1,4):
temp_list.append(l + str(n))
dict_config[l] = temp_list
temp_list = []
print(dict_config)
В этом случае скрипт будет работать как положено.
Очистка списка на месте и создание нового списка (повторная инициализация)
Итак, существуют следующие способы очистки списка «на месте»:
temp_list.clear()
del temp_list[:]
temp_list*=0
При использовании этих способов очистки списка очищаются области памяти, в которых хранится список, а также очищаются копии списка, являющиеся ссылками на эту область памяти.
И есть один способ удалить список с помощью повторной инициализации:
temp_list = []
Повторное создание списка с тем же именем не приводит к потере копий списка, хранящихся в других переменных.