Рассмотрите следующий фрагмент на Python: def add_item(item, lst=[]): lst.append(item); return lst; Объясните, почему поведение функции может быть неожиданным при нескольких вызовах и предложите корректные альтернативы
Проблема: значение параметра по умолчанию вычисляется один раз при определении функции, поэтому при объявлении `lst=[]` эта один и тот же список будет использоваться при всех последующих вызовах. Из‑за этого функция накапливает элементы между вызовами — часто неожиданно. Пример неожиданного поведения: ``` def add_item(item, lst=[]): lst.append(item) return lst print(add_item('a')) # ['a'] print(add_item('b')) # ['a', 'b'] <-- ожидаешь ['b'], но список общий ``` Корректные альтернативы 1) Использовать sentinel `None` и создавать новый список внутри: ``` def add_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst ``` Каждый вызов без явного `lst` будет получать новый список. 2) Использовать неизменяемый дефолт и преобразование: ``` def add_item(item, lst=()): lst = list(lst) lst.append(item) return lst ``` Тоже даёт новый список при каждом вызове. 3) Если же цель — накапливать значения между вызовами (то есть поведение, которое вы получили, — желаемое), делайте это явно: используйте замыкание, атрибут функции или глобальную переменную, чтобы это было читаемо: ``` def make_adder(): lst = [] def add(item): lst.append(item) return lst return add adder = make_adder() adder('a') # ['a'] adder('b') # ['a','b'] ``` Вывод: используйте `None` (вариант 1) для большинства случаев, если не хотите скрытого общего состояния.
Пример неожиданного поведения:
```
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item('a')) # ['a']
print(add_item('b')) # ['a', 'b'] <-- ожидаешь ['b'], но список общий
```
Корректные альтернативы
1) Использовать sentinel `None` и создавать новый список внутри:
```
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
```
Каждый вызов без явного `lst` будет получать новый список.
2) Использовать неизменяемый дефолт и преобразование:
```
def add_item(item, lst=()):
lst = list(lst)
lst.append(item)
return lst
```
Тоже даёт новый список при каждом вызове.
3) Если же цель — накапливать значения между вызовами (то есть поведение, которое вы получили, — желаемое), делайте это явно: используйте замыкание, атрибут функции или глобальную переменную, чтобы это было читаемо:
```
def make_adder():
lst = []
def add(item):
lst.append(item)
return lst
return add
adder = make_adder()
adder('a') # ['a']
adder('b') # ['a','b']
```
Вывод: используйте `None` (вариант 1) для большинства случаев, если не хотите скрытого общего состояния.