Ответ вслух Junior Функции и области видимости спрашивают часто обновлено

Почему опасны изменяемые значения по умолчанию

Вопрос

Объясните, что не так с def f(items=[]) и как это исправить. Бывает ли такое поведение полезным?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Образцовый ответ: «Выражения значений по умолчанию вычисляются один раз, в момент выполнения def, обычно при импорте модуля. Результат хранится в атрибуте функции defaults.

Что должно прозвучать в ответе

  • Значение по умолчанию вычисляется один раз при выполнении def

  • Хранится в `f.__defaults__`, общий объект для всех вызовов

  • Изменения копятся между вызовами

  • Исправление: `None` и создание внутри функции

  • Та же проблема с `datetime.now()` и любым вычисляемым значением

  • Иногда используют сознательно как простой кеш, но это неочевидно

Что могут спросить следом

  • Что будет, если значение по умолчанию кортеж?
  • Как линтер ловит эту ошибку?

Разбор

Образцовый ответ: «Выражения значений по умолчанию вычисляются один раз, в момент выполнения def, обычно при импорте модуля. Результат хранится в атрибуте функции __defaults__. Если это изменяемый объект, например список, то все вызовы без этого аргумента работают с одним и тем же списком, и он копит данные между вызовами. Это классический баг, который всплывает в продакшене как утечка данных между запросами. Исправление стандартное: items=None, а внутри if items is None: items = []. Та же история с datetime.now() или uuid4() по умолчанию: значение зафиксируется при импорте. С неизменяемыми значениями, кортежем или строкой, проблемы нет, их нельзя испортить. Иногда трюк используют сознательно как кеш между вызовами, но для этого понятнее functools.cache. Линтеры ruff и pylint ловят изменяемые значения по умолчанию отдельным правилом».

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.