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


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

Re: Why do closures do this?

Started byTerry Reedy <tjreedy@udel.edu>
First post2011-08-28 00:19 -0400
Last post2011-09-16 13:50 -0700
Articles 2 — 2 participants

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

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Why do closures do this? Terry Reedy <tjreedy@udel.edu> - 2011-08-28 00:19 -0400
    Re: Why do closures do this? John Nagle <nagle@animats.com> - 2011-09-16 13:50 -0700

#12329 — Re: Why do closures do this?

FromTerry Reedy <tjreedy@udel.edu>
Date2011-08-28 00:19 -0400
SubjectRe: Why do closures do this?
Message-ID<mailman.501.1314505201.27778.python-list@python.org>
On 8/27/2011 11:45 PM, John O'Hagan wrote:
> Somewhat apropos of the recent "function principle" thread, I was recently surprised by this:
>
> funcs=[]
> for n in range(3):
>      def f():
>          return n
>      funcs.append(f)
>
>
>
> The last expression, IMO surprisingly, is [2,2,2], not [0,1,2]. Google tells me I'm not the only one surprised, but explains that it's because "n" in the function "f" refers to whatever "n" is currently bound to, not what it was bound to at definition time (if I've got that right), and that there are at least two ways around it: either make a factory function:

def f(): return n
is a CONSTANT value. It is not a closure.

Your code above is the same as
def f(): return n
funcs = [f,f,f]
n = 2
[i() for i in funcs]

> def mkfnc(n):
>      def fnc():
>          return n
>      return fnc

fnc is a closure and n in a nonlocal name. Since you only read it, no 
nonlocal declaration is needed.

> funcs=[]
> for n in range(3):
>      funcs.append(mkfnc(n))
>
> which seems roundabout, or take advantage of the "default values set at definition time" behaviour:
>
> funcs=[]
> for n in range(3):
>      def f(n=n):
>          return n
>      funcs.append(f)
>
> which seems obscure, and a side-effect.

It was the standard idiom until nested functions were upgraded to 
enclose or capture the values of nonlocals.

> My question is, is this an inescapable consequence of using closures,

I cannot answer since I am not sure what you mean by 'this'.
Closures are nested functions that access the locals of enclosing 
functions. To ensure that the access remains possible even after the 
enclosing function returns, the last value of such accessed names is 
preserved even after the enclosing function returns. (That is the tricky 
part.)

-- 
Terry Jan Reedy

[toc] | [next] | [standalone]


#13399

FromJohn Nagle <nagle@animats.com>
Date2011-09-16 13:50 -0700
Message-ID<4e73b6a7$0$1667$742ec2ed@news.sonic.net>
In reply to#12329
On 8/27/2011 9:19 PM, Terry Reedy wrote:
> On 8/27/2011 11:45 PM, John O'Hagan wrote:
>> Somewhat apropos of the recent "function principle" thread, I was
>> recently surprised by this:
>>
>> funcs=[]
>> for n in range(3):
>> def f():
>> return n
>> funcs.append(f)
>>
>>
>>
>> The last expression, IMO surprisingly, is [2,2,2], not [0,1,2].

    That's correct behavior, because a closure captures the binding of
a nonlocal variable, not its value.  There is only one "n" for all
iterations.

    If you create a local variable within the closed function:

        def f()
            localn = n
            return(localn)

there's a copy of "localn" for each iteration, and you're returning
it.

Try this in PyPy, which tries not to box numbers, and see what happens
there.  This is one of those Python features which complicates
optimization.  For performance, an implementation should handle numbers
as machine numbers, not objects.  (Creating an object to hold a
machine primitive like an int, float, or bool is called "boxing' the
number.)  CPython always carries around a full
CObject for ordinary numbers, which is why CPython numeric performance
is so bad.  PyPy tries not to do that, although there are rare
cases when it has to, like this one.

					John Nagle

[toc] | [prev] | [standalone]


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


csiph-web