Дано (Python): def append_to_list(x, lst=[]): lst.append(x); return lst; — объясните, в чём проблема этой функции, как она ведёт себя при последовательных вызовах и предложите корректные варианты реализации
Проблема: в Python значение аргумента по умолчанию вычисляется один раз — когда функция определяется. Если это изменяемый объект (как `[]`), то все последующие вызовы без явного `lst` будут работать с одной и той же списочной инстанцией, поэтому элементы накапливаются. Поведение при последовательных вызовах (оригинальная функция): - вызов `append_to_list(1)` вернёт [1] [1] [1]
- затем `append_to_list(2)` вернёт [1,2] [1, 2] [1,2]
- затем `append_to_list(3)` вернёт [1,2,3] [1, 2, 3] [1,2,3]
Если же вызвать `append_to_list(4, [])`, вернётся [4] [4] [4] — при явном списке передаётся новый объект. Правильные варианты реализации: 1) Использовать `None` как «сентинел» и создавать новый список внутри функции (рекомендовано): def append_to_list(x, lst=None): if lst is None: lst = [] lst.append(x) return lst 2) Если нужно не изменять переданный список и всегда возвращать новый список: def append_to_list(x, lst=None): if lst is None: lst = [] return lst + [x] (здесь `lst` не мутирует — возвращается новая коллекция) 3) Явно требовать список от вызывающего (если разделение состояния нежелательно): def append_to_list(x, lst): lst.append(x) return lst Краткое замечание: первый вариант — стандартный способ избежать «ущербной» мутируемой константы по умолчанию.
Поведение при последовательных вызовах (оригинальная функция):
- вызов `append_to_list(1)` вернёт [1] [1] [1] - затем `append_to_list(2)` вернёт [1,2] [1, 2] [1,2] - затем `append_to_list(3)` вернёт [1,2,3] [1, 2, 3] [1,2,3] Если же вызвать `append_to_list(4, [])`, вернётся [4] [4] [4] — при явном списке передаётся новый объект.
Правильные варианты реализации:
1) Использовать `None` как «сентинел» и создавать новый список внутри функции (рекомендовано):
def append_to_list(x, lst=None):
if lst is None:
lst = []
lst.append(x)
return lst
2) Если нужно не изменять переданный список и всегда возвращать новый список:
def append_to_list(x, lst=None):
if lst is None:
lst = []
return lst + [x]
(здесь `lst` не мутирует — возвращается новая коллекция)
3) Явно требовать список от вызывающего (если разделение состояния нежелательно):
def append_to_list(x, lst):
lst.append(x)
return lst
Краткое замечание: первый вариант — стандартный способ избежать «ущербной» мутируемой константы по умолчанию.