lambda in list comprehension acting funny

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Jul 14 03:46:45 EDT 2012


On Fri, 13 Jul 2012 21:53:10 -0700, rusi wrote:

> On Jul 14, 8:43 am, Steven D'Aprano <steve
> +comp.lang.pyt... at pearwood.info> wrote:
>> On Fri, 13 Jul 2012 19:31:24 -0700, rusi wrote:
>> > Consider the following
>>
>> > def foo(x):
>> >     i = 100
>> >     if x:
>> >         j = [i for i in range(10)]
>> >         return i
>> >     else:
>> >         return i
>>
>> A simpler example:
>>
>> def foo():
>>     i = 100
>>     j = [i for i in range(10)]
>>     return i
>>
>> In Python 3, foo() returns 100; in Python 2, it returns 9.
> 
> You did not get the point.

I got the point. I just thought it was unnecessarily complex and that it 
doesn't demonstrate what you think it does.


> Converting my example to your format:
> 
> def foo_steven(n):
>     i = 100
>     j = [i for i in range(n)]
>     return i
> 
> $ python3
> Python 3.2.3 (default, Jun 26 2012, 00:38:09) [GCC 4.7.1] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
>>>> def foo_steven(n):
> ...     i = 100
> ...     j = [i for i in range(n)]
> ...     return i
> ...
>>>> foo_steven(0)
> 100
>>>> foo_steven(4)
> 100

Yes, we know that in Python 3, list comprehensions create their own 
scope, and the loop variable does not leak.


> $ python
> Python 2.7.3rc2 (default, Apr 22 2012, 22:35:38) [GCC 4.6.3] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
>>>> def foo_steven(n):
> ...     i = 100
> ...     j = [i for i in range(n)]
> ...     return i
> ...
>>>> foo_steven(0)
> 100
>>>> foo_steven(3)
> 2

Yes, we know that in Python 2, list comprehensions don't create their own 
scope, and consequently the list variable does leak.


> Python 2:
> When n>0 comprehension scope i is returned 
> When n=0 function scope i is returned

Incorrect.

In Python 2, *there is no comprehension scope*. There is only local 
scope. In Python 2, regardless of the value of n, the local variable i is 
ALWAYS returned. It just happens that sometimes the local variable i is 
modified by the list comprehension, and sometimes it isn't. In Python 2, 
this is no more mysterious than this piece of code:

def example(n):
    i = 100
    for i in range(n):
        pass
    return i

py> example(0)
100
py> example(4)
3

If the loop doesn't execute, the loop variable isn't modified. In Python 
2, it doesn't matter whether you use a for-loop or a list comprehension, 
the loop variable is local to the function.


 
> Python 3: The return statement is lexically outside the comprehension
> and so that outside-scope's i is returned in all cases.

Correct. In Python 3, list comprehensions now match generator expressions 
and introduce their own scope which does not effect the local function 
scope.

Some history:

http://bugs.python.org/issue510384
http://bugs.python.org/issue1110705




-- 
Steven



More information about the Python-list mailing list