В коде на Python def append_item(x, lst=[]): lst.append(x); return lst; объясните, почему вызовы append_item(1), append_item(2) дают неожиданные результаты, опишите природу ошибки и предложите корректные варианты реализации и тесты

26 Мая в 10:27
13 +1
0
Ответы
1
Проблема: в Python значение аргумента по умолчанию вычисляется один раз при определении функции и переиспользуется при последующих вызовах. Если это изменяемый объект (например, список), все вызовы будут работать с одной и той же общей структурой.
Пример симптома
- Определение: `def append_item(x, lst=[]): lst.append(x); return lst`
- Вызовы `append_item(1)` затем `append_item(2)` дадут не ожидаемые независимые списки, а накопление: первый вызов вернёт [1][1][1], второй — [1,2][1, 2][1,2].
Природа ошибки
- Это не «баг» интерпретатора, а семантика: лист `lst=[]` создаётся при загрузке тела функции и живёт между вызовами. Если вы изменяете этот объект внутри функции, изменения видны в последующих вызовах — получается скрытое состояние.
Корректные варианты реализации
1) Стандартный паттерн с `None`:
```python
def append_item(x, lst=None):
if lst is None:
lst = []
lst.append(x)
return lst
```
2) С проверкой уникального маркера (если `None` может быть допустимым значением):
```python
_sentinel = object()
def append_item(x, lst=_sentinel):
if lst is _sentinel:
lst = []
lst.append(x)
return lst
```
3) Функциональный подход — не изменять входной список, возвращать новый:
```python
def append_item(x, lst=None):
if lst is None:
lst = []
return lst + [x] # создаёт новый список
```
Простые тесты (assert):
```python
# Тест для проблемного варианта (демонстрация неправильного поведения)
def buggy():
def append_item(x, lst=[]):
lst.append(x)
return lst
a = append_item(1)
b = append_item(2)
return a, b
assert buggy()[0] == [1]
assert buggy()[1] == [1, 2] # неожиданно: второй список содержит элемент из первого
# Тесты для корректного варианта (ожидаемое поведение)
def correct():
def append_item(x, lst=None):
if lst is None:
lst = []
lst.append(x)
return lst
a = append_item(1)
b = append_item(2)
return a, b
assert correct()[0] == [1]
assert correct()[1] == [2] # правильно: состояния не смешиваются
```
Краткое резюме: не используйте изменяемые объекты как значения по умолчанию; применяйте `None` (или маркер) и создавайте новую структуру внутри функции, либо возвращайте новый объект вместо модификации входного.
26 Мая в 11:35
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир