Изменяемый аргумент по умолчанию в Python
@python_quizРазберем этот квиз
Коротко: невидимая общая переменная. В примере функция использует изменяемый объект (список) как значение по умолчанию — этот объект создаётся один раз при определении функции и затем используется повторно при всех вызовах, если аргумент не передан.
Условие (код)

Что выведет программа
Если выполнить этот код, вывод будет:

Почему оба вывода показывают [1, 1], а не, скажем, [1] и [1, 1]? Разберём пошагово.
Пошаговое объяснение
- При определении функции Python создаёт объект списка [] и привязывает его к параметру по умолчанию a.
- При первом вызове f() этот же список используется, в него добавляется 1 → список становится [1], функция возвращает ссылку на этот список.
- При втором вызове f() уже тот же самый список снова используется и в него добавляется ещё один 1 → список становится [1, 1], функция возвращает ссылку на тот же объект.
- В выражении print(f(), f()) оба вызова возвращают одну и ту же ссылку на объект. К моменту вывода строковое представление этого объекта отражает его текущее состояние — [1, 1] — поэтому оба аргумента печатаются как [1, 1].
Важно: аргумент по умолчанию не пересоздаётся при каждом вызове — это ключ к пониманию поведения.
Анализ вариантов ответов (пояснения)
- Выведет: [1] [1]
Такой результат был бы при создании нового списка при каждом вызове. Но здесь список общий, поэтому неверно.
- Выведет: [1] [1, 1]
Интуитивно кажется логичным: первый вызов дал [1], второй — [1,1]. Однако оба результата ссылаются на один и тот же объект, и когда второй вызов модифицирует список, это отражается и на первом результате при финальном выводе.
- Выведет: [1, 1] [1, 1]
Соответствует реальному поведению: один и тот же изменяемый объект используется повторно, и оба вывода показывают финальное состояние списка.
- Выбросит исключение
Исключения не происходит: операции с списком и вызовы выполняются корректно.
Как правильно писать, чтобы избежать сюрпризов
Если вы не хотите, чтобы аргумент сохранял состояние между вызовами, используйте образец с None:

Это гарантирует, что при каждом вызове создаётся новый список.
Практические замечания и рекомендации
- Такой паттерн — частая ловушка для новичков. Он встречается при использовании списков, словарей и других изменяемых типов.
- Иногда сохранение состояния между вызовами полезно (кеширование, накапливание), но если это не намеренное поведение — лучше явно создавать новый объект внутри функции.
- Для неизменяемых типов (int, str, tuple) подобной проблемы нет, потому что их нельзя изменять.
Заключение: изменяемые значения по умолчанию создаются один раз при определении функции. Если не хотите разделять объект между вызовами — используйте None и создавайте новый объект внутри функции.