Найдите баг и объясните причину в следующем Python‑коде: def append_item(item, lst=[]): lst.append(item); return lst; — почему поведение иногда неожиданное, как это связано со временем создания объектов по умолчанию, и какие корректные альтернативы
Баг: при объявлении `def append_item(item, lst=[]): ...` дефолтный аргумент `lst` — изменяемый объект — создаётся один раз при определении функции и затем переиспользуется во всех вызовах. Из‑за этого список накапливает элементы между вызовами: например `append_item(1)` вернёт [1][1][1], затем `append_item(2)` вернёт [1,2][1,2][1,2] (а не отдельный новый список). Причина (кратко): дефолтные значения вычисляются в момент определения функции (обычно при загрузке модуля), а не при каждом вызове. Поэтому один и тот же объект используется повторно. Правильные альтернативы: - Использовать `None` как маркер и создавать новый список внутри: def append_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst - Использовать явный «фабричный» аргумент / sentinel: _SENTINEL = object() def append_item(item, lst=_SENTINEL): if lst is _SENTINEL: lst = [] lst.append(item) return lst - Использовать неизменяемые типы (например кортеж) если это применимо, или копировать дефолтный список перед изменением: def append_item(item, lst=None): lst = list(lst) if lst is not None else [] lst.append(item) return lst Короткий вывод: не ставьте изменяемые объекты (`[]`, `{}` и т. п.) как значения по умолчанию; вместо этого создавайте их внутри функции (обычно через `None`).
Причина (кратко): дефолтные значения вычисляются в момент определения функции (обычно при загрузке модуля), а не при каждом вызове. Поэтому один и тот же объект используется повторно.
Правильные альтернативы:
- Использовать `None` как маркер и создавать новый список внутри:
def append_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
- Использовать явный «фабричный» аргумент / sentinel:
_SENTINEL = object()
def append_item(item, lst=_SENTINEL):
if lst is _SENTINEL:
lst = []
lst.append(item)
return lst
- Использовать неизменяемые типы (например кортеж) если это применимо, или копировать дефолтный список перед изменением:
def append_item(item, lst=None):
lst = list(lst) if lst is not None else []
lst.append(item)
return lst
Короткий вывод: не ставьте изменяемые объекты (`[]`, `{}` и т. п.) как значения по умолчанию; вместо этого создавайте их внутри функции (обычно через `None`).