Рассмотрите этот фрагмент на Python: def func(a=[]): a.append(1); return a; Объясните, почему вызовы func() ведут себя неочевидно, какие механизмы языка за этим стоят и как правильно исправить код

7 Мая в 16:08
13 +1
0
Ответы
1
Коротко — потому что default-параметр `a=[]` создаётся один раз при определении функции и затем повторно используется при всех вызовах. Пояснение и исправления:
Почему так происходит
- В Python значения аргументов по умолчанию вычисляются один раз при создании функции (не при каждом вызове).
- Если это изменяемый объект (список, словарь и т.п.), то изменения (например, `append`) сохраняются в этом же объекте и видны в последующих вызовах.
- По сути все вызовы без явного аргумента получают ссылку на один и тот же список.
Демонстрация (поведение)
```python
def func(a=[]):
a.append(1)
return a
print(func()) # [1]
print(func()) # [1, 1]
print(func()) # [1, 1, 1]
```
Как это исправить (рекомендованный вариант)
- Использовать sentinel `None` и при необходимости создавать новый список внутри функции:
```python
def func(a=None):
if a is None:
a = []
a.append(1)
return a
```
Теперь каждый вызов без аргумента создаёт новый список:
```python
print(func()) # [1]
print(func()) # [1]
```
Альтернативы и примечания
- Если хотите не мутировать переданный список, сделайте копию: `a = list(a)` или `a = a.copy()`.
- Если вам нужно именно одноразовое кэширование/накопление состояния между вызовами, то использование изменяемого default может быть намеренным (но это редкий паттерн и его стоит явно документировать).
- Можно также возвращать новый список без мутаций: `return (a or []) + [1]`.
Дополнительно: можно посмотреть текущее значение default через `func.__defaults__`, там хранится объект по умолчанию.
7 Мая в 16:14
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир