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