Любой, кто возился с Python достаточно долго, был укушен (или разорван на части) следующей проблемой:
def foo(a=[]):
a.append(5)
return a
Python послушники бы ожидать эта функция всегда возвращает список только с одним элементом: [5]
. Результат вместо этого очень отличается, и очень удивительно (для новичка):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Один мой менеджер однажды познакомился с этой функцией и назвал ее «драматическим недостатком дизайна» языка. Я ответил, что поведение имело под собой объяснение, и это действительно очень удивительно и неожиданно, если вы не понимаете внутренностей. Однако я не смог ответить (сам себе) на следующий вопрос: в чем причина привязки аргумента по умолчанию при определении функции, а не при выполнении функции? Я сомневаюсь, что опытное поведение имеет практическое применение (кто на самом деле использовал статические переменные в C, без выявления ошибок?)
Редактировать :
Бачек сделал интересный пример. Вместе с большинством ваших комментариев и комментариев Утаала, в частности, я уточнил:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Мне кажется, что проектное решение было относительно того, куда поместить область параметров: внутри функции или «вместе» с ней?
Выполнение привязки внутри функции будет означать, что x
она эффективно привязана к указанному значению по умолчанию, когда функция вызывается, а не определяется, что может представлять собой серьезный недостаток: def
линия будет «гибридной» в том смысле, что часть привязки (из объект функции) будет происходить при определении, а часть (назначение параметров по умолчанию) - во время вызова функции.
Фактическое поведение является более последовательным: все, что в этой строке, оценивается при выполнении этой строки, то есть при определении функции.
[5]
" Я новичок в Python, и я не ожидал бы этого, потому что, очевидно foo([1])
, вернется [1, 5]
, а не [5]
. Что вы хотели сказать, так это то, что новичок ожидал, что функция, вызываемая без параметра , всегда будет возвращаться [5]
.