tags:

views:

121

answers:

5

I'm trying to get my head around lambda expressions, closures and scoping in Python. Why does the program not crash on the first line here?

>>> 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
>>> 
+2  A: 

Your lambda expression doesn't get evaluated until you call it.

It does get parsed, which is why a syntax error would cause a traceback.

>>> foo = lambda x : x + a
>>> bar = lambda y : print y
SyntaxError: invalid syntax
Ryan Ginstrom
A: 

The bodies of lambdas (and functions defined with def) in Python are not evaluated until they are called. Names are always looked up at runtime.

Mike Graham
A: 

on the first line you create expression, which is different from evaluating it. When you try to evaluate it, this is then it cannot find symbol a .

aaa
+4  A: 

Because that's just not how Python functions work; it's not special to lambdas:

>>> 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

Variables are looked up when used, not when a function is defined. They are even looked up each time the function is called, which you will definitely find unexpected if you're coming from a C background (for example), but this isn't a problem in Python.

Roger Pate
+2  A: 

Variables in Python may be used before they are set. This will generate a runtime error, not a syntax error. Here's an example using local variables:

>>> 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

This is in contrast to languages which consider dereferencing an unassigned or undefined variable a syntax error. Python doesn't "capture" the current state of lexical scope, it just uses references to mutable lexical scopes. Here's a demonstration:

>>> 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
Dietrich Epp