Mutable default arguments в Python: почему список накапливается
@python_quizРазберем этот квиз
Короткий разбор поведения функции с изменяемым аргументом по умолчанию и как его правильно избегать или использовать осознанно.
Исходный код

Что выведет этот фрагмент и почему — ниже разберём подробно.
Что происходит при выполнении
- При определении функции значение аргумента по умолчанию вычисляется один раз — в момент определения функции. В данном случае создаётся один список и привязывается как значение по умолчанию для параметра
users. - При первом вызове
add_user('Ann')элемент'Ann'добавляется в этот список, и функция возвращает['Ann']. - При втором вызове
add_user('Bob')функция использует тот же самый список (тот же объект), уже содержащий'Ann', добавляет'Bob'и возвращает['Ann', 'Bob'].
Таким образом, вывод будет:

Можно дополнительно убедиться: если вызвать функцию ещё раз, список продолжит накапливаться.

Разбор вариантов (кратко)
- Вариант "['Ann'] затем ['Bob']" не соответствует действительности — второй вызов не использует пустой список по умолчанию, он использует уже изменённый.
- Вариант "['Ann'] затем ['Ann', 'Bob']" — это то, что действительно произойдёт при запуске приведённого кода.
- Вариант "['Ann'] затем ['Bob', 'Ann']" неверен: порядок добавления сохраняется, добавление происходит в конец списка.
- Вариант с исключением тоже неверен: повторное использование того же списка не приводит к исключению — это нормальное поведение, просто часто неожиданное.
Как правильно (без побочных эффектов)
Если вы хотите, чтобы при каждом вызове функция начинала с чистого списка по умолчанию, используйте значение None и создавайте новый список внутри функции:

Этот шаблон универсален и предотвращает накапливание значений между вызовами.
Когда поведение с накоплением нужно
Иногда именно требуется сохранять состояние между вызовами. Тогда можно явно сделать это явным и читаемым, например:

Или просто оставить список по умолчанию, но это чаще приводит к неожиданностям у читателей кода. Явное хранение состояния (атрибут функции, глобальная переменная, объект/класс) делает намерение понятным.
Итоги и рекомендации
- Аргументы по умолчанию в Python вычисляются один раз — при определении функции.
- Не используйте изменяемые объекты (список, словарь, множества) как значения по умолчанию, если не хотите, чтобы они сохраняли состояние между вызовами.
- Для "нового" значения при каждом вызове используйте шаблон с
None. - Если нужно сохранять состояние — делайте это явно (атрибут функции, замыкание, объект), чтобы код был читаем и понятен другим разработчикам.