Я пытаюсь получить голову вокруг лямбда-выражений, закрытий и определяющий объем в Python. Почему программа не отказывает на первой строке здесь?
>>> foo = lambda x: x + a
>>> foo(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
NameError: global name 'a' is not defined
>>> a = 5
>>> foo(2)
7
>>>
Потому что так не работают функции Python; это не особенность лямбд:
>>> def foo(x):
... return x + a
>>> foo
<function foo at 0xb7dde454>
>>> foo(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
NameError: global name 'a' is not defined
Переменные ищутся при использовании, а не при определении функции. Они даже ищутся каждый раз при вызове функции, что покажется вам неожиданным, если вы работаете на языке C (например), но в Python это не проблема.
Ваше лямбда-выражение не вычисляется, пока вы его не вызовете.
Он анализируется, поэтому синтаксическая ошибка может вызвать обратную трассировку.
>>> foo = lambda x : x + a
>>> bar = lambda y : print y
SyntaxError: invalid syntax
Переменные в Python могут быть использованы до того, как они установлены. Это приведет к ошибке времени выполнения, а не к синтаксической ошибке. Вот пример использования локальных переменных:
>>> def f():
... return a
... a = 3
...
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment
В отличие от языков, в которых разыменование неназначенной или неопределенной переменной считается синтаксической ошибкой. Python не "фиксирует" текущее состояние лексической области видимости, он просто использует ссылки на изменяемые лексические области видимости. Вот демонстрация:
>>> def f(): return a
...
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in f
NameError: global name 'a' is not defined
>>> a = 3
>>> f()
3
Тела лямбда-выражений (и функций, определенных с помощью def) в Python не оцениваются до тех пор, пока они не будут вызваны. Имена всегда просматриваются во время выполнения.
в первой строке вы создаете выражение, что отличается от его оценки. Когда вы пытаетесь оценить его, оно не может найти символ a.