a lambda in a function

Burton Radons notrub-snodar at shaw.ca
Wed Dec 12 21:20:18 EST 2001

Fred Clare wrote:

> Why does interpreting the five lines:
> def func():
>   x = 1
>   add_one = lambda i: i+x
>   j = add_one(100)
> func()
> Give me:
>   Traceback (most recent call last):
>     File "test.py", line 6, in ?
>       func()
>     File "test.py", line 4, in func
>       j = add_one(100)
>     File "test.py", line 3, in <lambda>
>       add_one = lambda i: i+x
>   NameError: There is no variable named 'x'
> while interpreting the three lines:
> x = 1
> add_one = lambda i: i+x
> j = add_one(100)
> works just fine?

It's a matter of scope vagaries.  This is answered in the FAQ, question 
4.5 at (http://www.python.org/cgi-bin/faqw.py?req=show&file=faq04.005.htp):

4.5. When I define a function nested inside another function, the nested 
function seemingly can't access the local variables of the outer 
function. What is going on? How do I pass local data to a nested function?

Python does not have arbitrarily nested scopes. When you need to create 
a function that needs to access some data which you have available 
locally, create a new class to hold the data and return a method of an 
instance of that class, e.g.:

class MultiplierClass:
             def __init__(self, factor):
                 self.factor = factor
             def multiplier(self, argument):
                 return argument * self.factor

def generate_multiplier(factor):
             return MultiplierClass(factor).multiplier

twice = generate_multiplier(2)
         print twice(10)
         # Output: 20

An alternative solution uses default arguments, e.g.:

def generate_multiplier(factor):
             def multiplier(arg, fact = factor):
                 return arg*fact
             return multiplier

twice = generate_multiplier(2)
         print twice(10)
         # Output: 20


Note that this has been solved in the 2.1 series thanks to PEP 227 
(Nested Scopes), as a __future__ feature.  In 2.2 nested scopes were 
added as default.  If you can't upgrade or if your code has to work on 
older versions, you'll have to use default arguments.

The second works because you're adding variables to the global 
dictionary, rather than a local dictionary that is specific to that 
frame.  Hope that helps.

More information about the Python-list mailing list