Why do closures do this?

John Nagle nagle at animats.com
Fri Sep 16 22:50:45 CEST 2011


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



More information about the Python-list mailing list