Список как значение по умолчанию
Почему def f(spisok=[]) — ловушка, которая срабатывает не сразу.
Ловушка
def dobavit(chto, kuda=[]):
kuda.append(chto)
return kuda
dobavit("а") # ['а']
dobavit("б") # ['а', 'б'] ← откуда там «а»?
Значение по умолчанию создаётся один раз, в момент объявления функции. Все вызовы получают один и тот же список, и изменения в нём копятся между вызовами.
Почему так
def — это не объявление, а выполняемая строка. Когда Python до неё
доходит, он создаёт функцию и тут же вычисляет значения по умолчанию.
Один раз, а не при каждом вызове.
Для чисел и строк это незаметно: их нельзя изменить. Для списков, словарей и множеств — заметно и обидно.
Как надо
def dobavit(chto, kuda=None):
if kuda is None:
kuda = []
kuda.append(chto)
return kuda
None как значение по умолчанию и проверка внутри — общепринятая
запись. Увидев =None в чужом коде, вы почти наверняка видите
именно это.
Когда это всплывает
Хуже всего то, что ошибка не проявляется на первом вызове. Функция работает, тесты проходят, и только в работе, через неделю, появляются записи, которых никто не добавлял.
То же самое в другом виде
def obrabotat(dannye, nastroyki={}): # та же ловушка
def zapisat(stroki, bufer=set()): # и эта
Правило простое: в значениях по умолчанию только неизменяемое —
числа, строки, None, кортежи.