Почему в Python следующий код ведёт себя неожиданно? Объясните результат и предложите исправления. def add_item(x, lst=[]): lst.append(x) return lst print(add_item(1)) print(add_item(2))
Проблема в том, что значение аргумента по умолчанию вычисляется один раз — в момент определения функции. В вашем примере lst = создаётся одна и та же список-объект и затем переиспользуется при каждом вызове функции без явной передачи lst. Поэтому последовательные вызовы модифицируют один и тот же список.
Что у вас происходит:
Первый вызов add_item111 даёт 111.Второй вызов add_item222 добавляет 2 в уже существующий список -> 1,21, 21,2.
Иллюстрация можнопосмотретьidспискаможно посмотреть id спискаможнопосмотретьidсписка:
3) Если нужно принять уже существующий список, но не изменять переданный объект — делать копию:
def add_itemx,lst=Nonex, lst=Nonex,lst=None: if lst is None: lst =
else: lst = listlstlstlst # копия lst.appendxxx
return lst
Это не баг Python, а ожидаемое поведение. Для мутабельных объектов list,dict,setит.п.list, dict, set и т.п.list,dict,setит.п. по умолчанию лучше использовать None и создавать объект внутри функции.
Проблема в том, что значение аргумента по умолчанию вычисляется один раз — в момент определения функции. В вашем примере lst = создаётся одна и та же список-объект и затем переиспользуется при каждом вызове функции без явной передачи lst. Поэтому последовательные вызовы модифицируют один и тот же список.
Что у вас происходит:
Первый вызов add_item111 даёт 111.Второй вызов add_item222 добавляет 2 в уже существующий список -> 1,21, 21,2.Иллюстрация можнопосмотретьidспискаможно посмотреть id спискаможнопосмотретьidсписка:
def add_itemx,lst=[]x, lst=[]x,lst=[]:print′id(lst)=′,id(lst)'id(lst) =', id(lst)′id(lst)=′,id(lst) lst.appendxxx return lst
printadditem(1)add_item(1)addi tem(1) # id одинаковый
printadditem(2)add_item(2)addi tem(2)
Как исправить
def add_itemx,lst=Nonex, lst=Nonex,lst=None:1) Использовать "sentinel" None рекомендуемыйподходрекомендуемый подходрекомендуемыйподход:
if lst is None:
lst = lst.appendxxx return lst
printadditem(1)add_item(1)addi tem(1) # 111 printadditem(2)add_item(2)addi tem(2) # 222
2) Всегда передавать новый список при вызове:
printadditem(1,[])add_item(1, [])addi tem(1,[]) printadditem(2,[])add_item(2, [])addi tem(2,[])3) Если нужно принять уже существующий список, но не изменять переданный объект — делать копию:
def add_itemx,lst=Nonex, lst=Nonex,lst=None:if lst is None:
lst = else:
lst = listlstlstlst # копия
lst.appendxxx return lst
Это не баг Python, а ожидаемое поведение. Для мутабельных объектов list,dict,setит.п.list, dict, set и т.п.list,dict,setит.п. по умолчанию лучше использовать None и создавать объект внутри функции.