RELEASED Python 2.4, alpha 1

Michele Simionato michele.simionato at gmail.com
Sun Jul 11 00:11:22 EDT 2004


bokr at oz.net (Bengt Richter) wrote in message
> I guess I don't know what you mean by "late binding" -- i.e., I don't see
> a semantic difference between (I don't have the generator expression version yet):
> 
>  >>> f1,f2,f3=[lambda : i for i in [1,2,3]]
>  >>> f1(),f2(),f3()
>  (3, 3, 3)
> 
> and
> 
>  >>> lamb = lambda : i
>  >>> f1,f2,f3=[lamb for i in [1,2,3]]
>  >>> f1(),f2(),f3()
>  (3, 3, 3)
> 
> ISTM it is a matter of late lookup, more than late binding. I.e.,
> the lambda expression specifies lookup of a name "i" when it is executed:

Yes, I was unsure of the right term to use, I meant late lookup (so 
I used the term "early binding" improperly, but you understood what 
I asked anyway ;).

>  >>> import dis
>  >>> dis.dis(lambda : i)
>    1           0 LOAD_GLOBAL              0 (i)
>                3 RETURN_VALUE
> 
> The list comprehension didn't generate a different lookup:
>  >>> f1,f2,f3=[lambda : i for i in [1,2,3]]
>  >>> dis.dis(f1)
>    1           0 LOAD_GLOBAL              0 (i)
>                3 RETURN_VALUE
> 
> BTW, if list comprehension variables bound in a loop-private scope instead of
> the enclosing scope, the lookup of i would fail unless otherwise set ;-)
> Will generator expressions bind in the eclosing scope too? Have the consequences been discussed?

Python 2.4a1 (#1, Jul 10 2004, 02:19:27)
[GCC 3.3.1 (Mandrake Linux 9.2 3.3.1-2mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ls=[i for i in [1,2,3]]
>>> i
3
>>> it=(j for j in [1,2,3])
>>> j
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'j' is not defined

I like this.

> Anyway, as I think you know, to get your desired end result, you have to create lambdas
> that will do their lookups referring to different i's -- which you can do with closures, e.g.,
> 
>  >>> f1,f2,f3=[(lambda i: lambda : i)(i) for i in [1,2,3]]
>  >>> f1(),f2(),f3()
>  (1, 2, 3)
>  >>> dis.dis(f1)
>    1           0 LOAD_DEREF               0 (i)
>                3 RETURN_VALUE
> 
> Or here's another of several other possible ways:
> 
>  >>> f1,f2,f3=[(lambda i:i).__get__(i,int) for i in [1,2,3]]
>  >>> f1(),f2(),f3()
>  (1, 2, 3)
>  >>> dis.dis(f1)
>    1           0 LOAD_FAST                0 (i)
>                3 RETURN_VALUE
> 
> BTW, those are bound methods ...
>  >>> f1,f2,f3
>  (<bound method int.<lambda> of 1>, <bound method int.<lambda> of 2>, <bound method int.<lambda> of 3>)

Yes Bengt, but would you seriously use such "solutions"? The default argument
trick is ugly but far better than those horrors! ;) What I do in reality
is to I create a custom function factory (or a factory of callable
objects) and I pass it to the list comprehension with "i" as a parameter.
My complaint is that it is more verbose than I would like for short 
functions where  I would consider a "lambda".

               Michele Simionato


                 Michele



More information about the Python-list mailing list