Мутабельный аргумент по умолчанию в Python

Мутабельный аргумент по умолчанию в Python

@python_quiz

Разберем этот квиз

Коротко и по существу: небольшая функция демонстрирует распространённую ловушку — использование изменяемого объекта (списка) как значения аргумента по умолчанию.

Код задачи

python

Что печатает код

При запуске программа выведет:

То есть первый вызов возвращает список с одним элементом, второй — с двумя элементами, причём первый элемент сохраняется между вызовами.

Почему так происходит — объяснение механизма

  • Значение аргументов по умолчанию в Python вычисляется один раз — в момент определения функции, а не при каждом вызове.
  • Если значение по умолчанию — изменяемый объект (список, словарь, множество и т.п.), то все вызовы функции без передачи этого аргумента будут работать с одним и тем же объектом.
  • В нашем примере lst указывает на один и тот же список при первом и втором вызове. После extend_list(1) внутри этого единого списка появляется 1. При втором вызове extend_list(2) функция добавляет 2 в тот же список, поэтому результат [1, 2].

Дополнительная демонстрация того, что это один и тот же объект:

python

Вы увидите одинаковые id для обоих вызовов.

Разбор возможных вариантов (почему другие варианты неверны)

  • "[1]\n[2]": Такой вывод бы получился, если бы при каждом вызове создавался новый список по умолчанию. Но это не соответствует правилам Python — значение по умолчанию создаётся один раз.
  • "[1]\n[2, 1]": Порядок элементов показывает, что при втором вызове элемент добавился в начало или произошла перестановка; в реальном коде используется append (вставка в конец), так что порядок будет [1, 2].
  • "Ошибка из-за повторного использования аргумента по умолчанию": Повторное использование изменяемого аргумента не вызывает исключение — это легальная (хотя и часто нежелательная) особенность языка.

Как избежать такой «подсказки» в будущем

Правильный и безопасный паттерн — использовать None как значение по умолчанию и создавать новый список внутри функции, если требуется:

python

Теперь вывод будет:

Каждый вызов без явного аргумента получает новый список.

Альтернативы:

  • Всегда передавать явный пустой список при вызове: extend_list(1, []).
  • Использовать иммутабельные структуры (кортежи) или возвращать новый объект вместо модификации входного.

Вывод

Избегайте использования изменяемых объектов в качестве значений по умолчанию, если вы не хотите, чтобы состояние сохранялось между вызовами. Паттерн с None — простой и надёжный способ обеспечить ожидаемое поведение функции.

Report Page