Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #25166 > unrolled thread

lambda in list comprehension acting funny

Started byDaniel Fetchinson <fetchinson@googlemail.com>
First post2012-07-11 08:41 +0200
Last post2012-07-13 13:47 -0400
Articles 8 on this page of 48 — 18 participants

Back to article view | Back to comp.lang.python


Contents

  lambda in list comprehension acting funny Daniel Fetchinson <fetchinson@googlemail.com> - 2012-07-11 08:41 +0200
    Re: lambda in list comprehension acting funny "Colin J. Williams" <cjw@ncf.ca> - 2012-07-11 06:28 -0400
      Re: lambda in list comprehension acting funny Ian Kelly <ian.g.kelly@gmail.com> - 2012-07-11 10:34 -0600
        Re: lambda in list comprehension acting funny 88888 Dihedral <dihedral88888@googlemail.com> - 2012-07-11 20:39 -0700
          Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-12 03:51 +0000
            Re: lambda in list comprehension acting funny 88888 Dihedral <dihedral88888@googlemail.com> - 2012-07-11 22:04 -0700
              Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-12 06:18 +0000
                Re: lambda in list comprehension acting funny Mark Lawrence <breamoreboy@yahoo.co.uk> - 2012-07-12 08:40 +0100
        Re: lambda in list comprehension acting funny 88888 Dihedral <dihedral88888@googlemail.com> - 2012-07-11 20:39 -0700
    Re: lambda in list comprehension acting funny woooee <woooee@gmail.com> - 2012-07-11 11:38 -0700
      Re: lambda in list comprehension acting funny John Ladasky <john_ladasky@sbcglobal.net> - 2012-07-11 13:21 -0700
        Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-12 00:52 +0000
        Re: lambda in list comprehension acting funny Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2012-07-11 21:05 -0400
          Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-12 03:53 +0000
            Re: lambda in list comprehension acting funny Terry Reedy <tjreedy@udel.edu> - 2012-07-12 00:24 -0400
            Re: lambda in list comprehension acting funny Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2012-07-12 00:39 -0400
              Re: lambda in list comprehension acting funny Robert Miles <robertmiles@teranews.com> - 2012-08-15 19:26 -0500
        Re: lambda in list comprehension acting funny John O'Hagan <research@johnohagan.com> - 2012-07-12 15:29 +1000
        Re: lambda in list comprehension acting funny Robert Kern <robert.kern@gmail.com> - 2012-07-12 10:06 +0100
      Re: lambda in list comprehension acting funny Hans Mulder <hansmu@xs4all.nl> - 2012-07-12 00:22 +0200
      Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-11 23:47 +0000
        Re: lambda in list comprehension acting funny Daniel Fetchinson <fetchinson@googlemail.com> - 2012-07-12 04:54 +0200
    Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-12 03:59 +0000
      Re: lambda in list comprehension acting funny Ian Kelly <ian.g.kelly@gmail.com> - 2012-07-12 10:53 -0600
      Re: lambda in list comprehension acting funny Rotwang <sg552@hotmail.co.uk> - 2012-07-12 18:23 +0100
        Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-13 02:20 +0000
    Re: lambda in list comprehension acting funny rusi <rustompmody@gmail.com> - 2012-07-12 21:33 -0700
      Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-13 06:36 +0000
        Re: lambda in list comprehension acting funny rusi <rustompmody@gmail.com> - 2012-07-13 06:44 -0700
          Re: lambda in list comprehension acting funny rusi <rustompmody@gmail.com> - 2012-07-13 07:45 -0700
          RE: lambda in list comprehension acting funny "Prasad, Ramit" <ramit.prasad@jpmorgan.com> - 2012-07-13 16:12 +0000
            Re: lambda in list comprehension acting funny rusi <rustompmody@gmail.com> - 2012-07-13 09:46 -0700
              Re: lambda in list comprehension acting funny Chris Angelico <rosuav@gmail.com> - 2012-07-14 03:20 +1000
            Re: lambda in list comprehension acting funny Hans Mulder <hansmu@xs4all.nl> - 2012-07-13 19:53 +0200
              RE: lambda in list comprehension acting funny "Prasad, Ramit" <ramit.prasad@jpmorgan.com> - 2012-07-13 18:06 +0000
              Re: lambda in list comprehension acting funny Ian Kelly <ian.g.kelly@gmail.com> - 2012-07-13 12:54 -0600
                Re: lambda in list comprehension acting funny Hans Mulder <hansmu@xs4all.nl> - 2012-07-13 21:26 +0200
                Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-14 23:29 +0000
                  Re: lambda in list comprehension acting funny Chris Angelico <rosuav@gmail.com> - 2012-07-15 10:49 +1000
                    Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-15 08:32 +0000
                      Re: lambda in list comprehension acting funny Chris Angelico <rosuav@gmail.com> - 2012-07-15 18:44 +1000
                        Re: lambda in list comprehension acting funny Hans Mulder <hansmu@xs4all.nl> - 2012-07-15 21:25 +0200
                      Re: lambda in list comprehension acting funny Terry Reedy <tjreedy@udel.edu> - 2012-07-15 06:27 -0400
              Re: lambda in list comprehension acting funny rusi <rustompmody@gmail.com> - 2012-07-13 19:31 -0700
                Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-14 03:43 +0000
                  Re: lambda in list comprehension acting funny rusi <rustompmody@gmail.com> - 2012-07-13 21:53 -0700
                    Re: lambda in list comprehension acting funny Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-14 07:46 +0000
          Re: lambda in list comprehension acting funny Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2012-07-13 13:47 -0400

Page 3 of 3 — ← Prev page 1 2 [3]


#25342

FromChris Angelico <rosuav@gmail.com>
Date2012-07-15 18:44 +1000
Message-ID<mailman.2133.1342341852.4697.python-list@python.org>
In reply to#25340
On Sun, Jul 15, 2012 at 6:32 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> At compile time, Python parses the source code and turns it into byte-
> code. Class and function definitions are executed at run time, the same
> as any other statement.

Between the parse step and the 'def' execution, a code object is
created. When you call it, that code object already exists. Nothing
else really matters, unless there's a bug in the Python optimizer or
something weird like that. The nearest thing Python _has_ to a
"compile time" is the execution of def.

ChrisA

[toc] | [prev] | [next] | [standalone]


#25369

FromHans Mulder <hansmu@xs4all.nl>
Date2012-07-15 21:25 +0200
Message-ID<50031945$0$6955$e4fe514c@news2.news.xs4all.nl>
In reply to#25342
On 15/07/12 10:44:09, Chris Angelico wrote:
> On Sun, Jul 15, 2012 at 6:32 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> At compile time, Python parses the source code and turns it into byte-
>> code. Class and function definitions are executed at run time, the same
>> as any other statement.
> 
> Between the parse step and the 'def' execution, a code object is
> created. When you call it, that code object already exists. Nothing
> else really matters, unless there's a bug in the Python optimizer or
> something weird like that. The nearest thing Python _has_ to a
> "compile time" is the execution of def.
> 
> ChrisA

"Compile time" is the phase when your Python code is turned into byte
code, or a SyntaxError is raised.  In this phase, a "code object" is
created for the function.

"Function definition time" is when the "def" command is executed.
In this phase, default arguments are computed, and a "function object"
is created.  Among the attributes of the function object are the code
object, and "cell" objects containing the bindings for its non-local
variables.  These bindings are used to read the variable's current
value at the time the function uses the variable.


-- HansM

[toc] | [prev] | [next] | [standalone]


#25345

FromTerry Reedy <tjreedy@udel.edu>
Date2012-07-15 06:27 -0400
Message-ID<mailman.2136.1342348081.4697.python-list@python.org>
In reply to#25340
On 7/15/2012 4:32 AM, Steven D'Aprano wrote:
> On Sun, 15 Jul 2012 10:49:48 +1000, Chris Angelico wrote:
>
>> On Sun, Jul 15, 2012 at 9:29 AM, Steven D'Aprano
>> <steve+comp.lang.python@pearwood.info> wrote:
>>> Not necessarily *compile* time, but the distinction is between when the
>>> function is defined (which may at compile time, or it may be at run
>>> time) versus when the function is called.
>>
>> I'd treat the def/lambda statement as "compile time" and the () operator
>> as "run time".
>
> But function definitions occur at run time, not compile time -- they are
> executable statements, not instructions to the compiler to define a
> function.

The () operator is 'call time'. The main points are
a) the execution of def statements and lambda expressions and the 
execution of calls happen at different run times.
b) default arg objects are calculated at def/lambda time.
c) names in def bodies and lambda expressions are resolved at call time.
and
d) people more often forget c) when thinking about lambda expressions 
that for def statements.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#25301

Fromrusi <rustompmody@gmail.com>
Date2012-07-13 19:31 -0700
Message-ID<6d0f3582-0e34-4fa1-926d-7725ba275410@q5g2000pba.googlegroups.com>
In reply to#25279
On Jul 13, 10:53 pm, Hans Mulder <han...@xs4all.nl> wrote:
> If you add `global VERBOSE` to `caller`, then there is only one
> variable named `VERBOSE` and what `function` does, depends on
> the most recent assignment to that variable.
>
> If you remove your `global VERBOSE`, then there are two
> variables by that name, one global and one local to `caller`.
> In that case, there is the question of which one `function`
> will use.

Good point. See below.

>
> The function `function` refers to a variable `VERBOSE` that
> isn't local.  In some programming langauages, the interpreter
> would then scan the call stack at run-time, looking for a scope
> where that name is defined.  It would find the local one in
> `caller`.  This is known as "dynamic binding".
>
> Other interpreters use the `VERBOSE` that was in scope at
> the point in the program text where `function` was defined.
> In this case, that would be the global one.  This is called
> "lexical binding".
>
> Some programming languages allow you to indicate on a per-
> variable basis whether you want dynamic or lexical binding.
>
> Python is firmly in the lexical camp.  Dynamic binding is not
> available in Python, and never will be.

Thats a good intention.  The question is whether it is uniformly
realized.

Consider the following

def foo(x):
    i = 100
    if x:
        j = [i for i in range(10)]
        return i
    else:
        return i

In python 2  two different 'i's could be returned. In python3 only one
i can be returned.
One could call it dynamic binding. Evidently Guido thinks it a bug
which is why he changed it.

The leakage of i in the OPs question is the same kind of bug.

tl;dr version:
This is 2012. Dynamic binding is considered a bug even by the lisp
community where it originated.
Lets at least call it a feature and a gotcha

[toc] | [prev] | [next] | [standalone]


#25303

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-07-14 03:43 +0000
Message-ID<5000eadb$0$29995$c3e8da3$5496439d@news.astraweb.com>
In reply to#25301
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.


> In python 2  two different 'i's could be returned. In python3 only one i
> can be returned.
> One could call it dynamic binding. 

One could also call it a tractor, but it isn't either of those things.

The difference is whether or not list comprehensions create their own 
scope. In Python 2, they don't; in Python 3, they do. Personally I don't 
have an opinion as to which is better, but in neither case does this have 
any thing to do with lexical versus dynamic binding.


> Evidently Guido thinks it a bug which is why he changed it.

It was a case that either list comps be changed to *not* expose their 
loop variable, or generator expressions be changed *to* expose their loop 
variable. The Python 2 situation where list comps and gen expressions 
have opposite behaviour was unfortunate.


> The leakage of i in the OPs question is the same kind of bug.

Not at all. The OP was *deliberately* creating a closure using i -- under 
those circumstances, it would be a bug if i *didn't* leak.

The OP's gotcha was:

1) he expected the closure to use early binding, where i in each function 
was bound to the value of i in the enclosing scope at the moment the 
function was defined; 

2) but Python actually uses late binding for closures, where the value of 
i in each function is set to the value of i in the enclosing scope when 
the function is called.

As far as I can tell, Python always uses late binding for scopes; the 
only time it does early binding is for default values of function 
parameters.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#25304

Fromrusi <rustompmody@gmail.com>
Date2012-07-13 21:53 -0700
Message-ID<70a01a5b-a884-4d41-b313-da2fefd2d825@l6g2000pbf.googlegroups.com>
In reply to#25303
On Jul 14, 8:43 am, Steven D'Aprano <steve
+comp.lang.pyt...@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.

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
>>>
$ 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
>>>

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

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

[toc] | [prev] | [next] | [standalone]


#25306

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-07-14 07:46 +0000
Message-ID<500123e5$0$29995$c3e8da3$5496439d@news.astraweb.com>
In reply to#25304
On Fri, 13 Jul 2012 21:53:10 -0700, rusi wrote:

> On Jul 14, 8:43 am, Steven D'Aprano <steve
> +comp.lang.pyt...@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

[toc] | [prev] | [next] | [standalone]


#25277

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2012-07-13 13:47 -0400
Message-ID<mailman.2092.1342201638.4697.python-list@python.org>
In reply to#25263
On Fri, 13 Jul 2012 06:44:59 -0700 (PDT), rusi <rustompmody@gmail.com>
declaimed the following in gmane.comp.python.general:


> Heres a more appropriate analog
> 
> ------------------------------------------
> VERBOSE = True
> 
> def function(arg):
>     if VERBOSE:
>        print("calling function with arg %r" % arg)
>     process(arg)
> 
> def caller():
>     VERBOSE = False
>     function(1)
> 
> ---------------------------------------------
> Python semantics: function sees VERBOSE False

	Wrong... "function" still sees the module level VERBOSE with a value
of True, whereas "caller" created a local VERBOSE set to False. To get
your behavior needs:

	def caller():
		global VERBOSE
		VERBOSE = False
		function(1)


> Haskell semantics: function sees VERBOSE True
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
        wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

[toc] | [prev] | [standalone]


Page 3 of 3 — ← Prev page 1 2 [3]

Back to top | Article view | comp.lang.python


csiph-web