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


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

Why do closures do this?

Started byJohn O'Hagan <research@johnohagan.com>
First post2011-08-28 13:45 +1000
Last post2011-08-28 14:16 -0700
Articles 3 — 2 participants

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


Contents

  Why do closures do this? John O'Hagan <research@johnohagan.com> - 2011-08-28 13:45 +1000
    Re: Why do closures do this? Carl Banks <pavlovevidence@gmail.com> - 2011-08-28 14:16 -0700
    Re: Why do closures do this? Carl Banks <pavlovevidence@gmail.com> - 2011-08-28 14:16 -0700

#12328 — Why do closures do this?

FromJohn O'Hagan <research@johnohagan.com>
Date2011-08-28 13:45 +1000
SubjectWhy do closures do this?
Message-ID<mailman.500.1314503122.27778.python-list@python.org>
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)

[i() for i in funcs]

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 mkfnc(n):
    def fnc():
        return n
    return fnc

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.

My question is, is this an inescapable consequence of using closures, or is it by design, and if so, what are some examples of where this would be the preferred behaviour?

Regards,

John 

[toc] | [next] | [standalone]


#12350

FromCarl Banks <pavlovevidence@gmail.com>
Date2011-08-28 14:16 -0700
Message-ID<mailman.515.1314566198.27778.python-list@python.org>
In reply to#12328
On Saturday, August 27, 2011 8:45:05 PM UTC-7, John O&#39;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)
> 
> [i() for i in funcs]
> 
> 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: ....
> My question is, is this an inescapable consequence of using closures, or is it by design, and if so, what are some examples of where this would be the preferred behaviour?


It is the preferred behavior for the following case.

def foo():
    def printlocals():
        print a,b,c,d
    a = 1; b = 4; c = 5; d = 0.1
    printlocals()
    a = 2
    printlocals()

When seeing a nested function, there are strong expectations by most people that it will behave this way (not to mention it's a lot more useful).  It's only for the less common and much more advanced case of creating a closure in a loop that the other behavior would be preferred.


Carl Banks

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


#12351

FromCarl Banks <pavlovevidence@gmail.com>
Date2011-08-28 14:16 -0700
Message-ID<f71c0969-d9d5-40b6-b8bb-7c08743c87ed@glegroupsg2000goo.googlegroups.com>
In reply to#12328
On Saturday, August 27, 2011 8:45:05 PM UTC-7, John O&#39;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)
> 
> [i() for i in funcs]
> 
> 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: ....
> My question is, is this an inescapable consequence of using closures, or is it by design, and if so, what are some examples of where this would be the preferred behaviour?


It is the preferred behavior for the following case.

def foo():
    def printlocals():
        print a,b,c,d
    a = 1; b = 4; c = 5; d = 0.1
    printlocals()
    a = 2
    printlocals()

When seeing a nested function, there are strong expectations by most people that it will behave this way (not to mention it's a lot more useful).  It's only for the less common and much more advanced case of creating a closure in a loop that the other behavior would be preferred.


Carl Banks

[toc] | [prev] | [standalone]


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


csiph-web