closures and dynamic binding

Terry Reedy tjreedy at
Sun Sep 28 23:47:44 CEST 2008

Aaron "Castironpi" Brady wrote:
> On Sep 28, 2:52 am, Steven D'Aprano <st... at REMOVE-THIS-

>> As for why the complicated version works, it may be clearer if you expand
>> it from a one-liner:
>> # expand: f[ n ]= (lambda n: ( lambda: n ) )( n )
>> inner = lambda: n
>> outer = lambda n: inner
>> f[n] = outer(n)
>> outer(0) => inner with a local scope of n=0
>> outer(1) => inner with a local scope of n=1 etc.

For this to work, the 'expansion' has to be mental and not actual.
Which is to say, inner must be a text macro to be substituted back into 

>> Then, later, when you call inner() it grabs the local scope and returns
>> the number you expected.

> I must have misunderstood.  Here's my run of your code:

I cannot speak to what Steven meant, but

>>>> inner = lambda: n

when inner is actually compiled outside of outer, it is no longer a 
closure over outer's 'n' and 'n' will be looked for in globals instead.

>>>> outer = lambda n: inner
>>>> outer(0)
> <function <lambda> at 0x00A01170>
>>>> a=outer(0)
>>>> b=outer(1)
>>>> a()
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 1, in <lambda>
> NameError: global name 'n' is not defined
> Why doesn't 'inner' know it's been used in two different scopes, and
> look up 'n' based on the one it's in?

That would be dynamic rather than lexical scoping.

More information about the Python-list mailing list