def f(a=[]):
a.append(1)
return a
print(f())
print(f())
Функция f(a=[])
использует изменяемый дефолтный аргумент a
(список). При первом вызове, a
инициализируется пустым списком, 1
добавляется в него, и список [1]
возвращается.
При втором вызове, a
не инициализируется заново, а сохраняет своё предыдущее значение ([1]
). Поэтому, 1
добавляется к уже существующему списку, и возвращается [1, 1]
.
Таким образом, вывод будет:
[1]
[1, 1]
Описание проблемы:
Данный код иллюстрирует распространенную ошибку, связанную с использованием изменяемых объектов (в данном случае, списка) в качестве значения аргумента по умолчанию в Python.
Объяснение работы кода:
f(a=[])
определена с аргументом a
, имеющим значение по умолчанию []
(пустой список). Важно понимать, что это только один объект-список, который создается один раз при определении функции.f()
(без аргументов), используется список по умолчанию []
. Внутри функции к этому списку добавляется элемент 1
, и список возвращается. Таким образом, выводится [1]
.f()
(снова без аргументов), снова используется тот же самый список, который был изменен при первом вызове. К нему добавляется еще один элемент 1
, и список возвращается. Таким образом, выводится [1, 1]
.Ожидаемый и фактический результат:
Наивный программист мог бы ожидать, что при каждом вызове f()
будет возвращаться [1]
. Однако, из-за поведения аргументов по умолчанию с изменяемыми типами, фактический результат будет:
[1]
[1, 1]
Правильное решение:
Чтобы избежать этой проблемы, рекомендуется использовать None
в качестве значения по умолчанию, а затем создавать список внутри функции, если аргумент не был передан:
def f(a=None):
if a is None:
a = []
a.append(1)
return a
print(f())
print(f())
В этом случае, при каждом вызове f()
, будет создаваться новый пустой список, и результат будет соответствовать ожидаемому:
[1]
[1]
Вывод:
При работе с аргументами по умолчанию в Python, особенно с изменяемыми типами данных, необходимо проявлять осторожность, чтобы избежать неожиданного поведения.