closures and dynamic binding
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Sun Sep 28 09:52:56 CEST 2008
On Sat, 27 Sep 2008 21:43:15 -0700, Aaron \"Castironpi\" Brady wrote:
> Hello all,
>
> To me, this is a somewhat unintuitive behavior. I want to discuss the
> parts of it I don't understand.
>
>>>> f= [ None ]* 10
>>>> for n in range( 10 ):
> ... f[ n ]= lambda: n
> ...
>>>> f[0]()
> 9
>>>> f[1]()
> 9
>
> I guess I can accept this part so far, though it took a little getting
> used to. I'm writing some code and found the following workaround, but
> I don't think it should give different results. Maybe I'm not
> understanding some of the details of closures.
>
>>>> f= [ None ]* 10
>>>> for n in range( 10 ):
> ... f[ n ]= (lambda n: ( lambda: n ) )( n )
> ...
>>>> f[0]()
> 0
>>>> f[1]()
> 1
>
> Which is of course the desired effect. Why doesn't the second one just
> look up what 'n' is when I call f[0], and return 9?
That's an awfully complicated solution. A much easier way to get the
result you are after is to give each function its own local copy of n:
f[n] = lambda n=n: n
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.
Then, later, when you call inner() it grabs the local scope and returns
the number you expected.
--
Steven
More information about the Python-list
mailing list