[Python-ideas] 'Injecting' objects as function-local constants

Terry Reedy tjreedy at udel.edu
Mon Jun 13 21:33:24 CEST 2011

On 6/13/2011 3:11 AM, Steven D'Aprano wrote:
> Terry Reedy wrote:

>> Or use closures, which were partly designed to replace default arg use.
> Default args are specifically used in at least one use-case where
> closures give the wrong result.

I meant an explicit user-defined closure with a separate cell for each 
function ...

>  >>> funcs = [lambda x: x+i for i in range(10)]
>  >>> funcs[0].__closure__ # may be different in Python 2.x
> (<cell at 0xb7bd8a1c: int object at 0x81b20c0>,)
>  >>> funcs[0](42) # should return 42+0
> 51

not this implicit one where each function uses the *same* cell referring 
to the same int object.

 >>> funcs[0].__closure__
(<cell at 0x00FE0330: int object at 0x1E2139A0>,)
 >>> funcs[9].__closure__
(<cell at 0x00FE0330: int object at 0x1E2139A0>,)

The fundamental problem with this code for funcs is that "lambda x: x+i" 
is a *constant* equivalent to "def _(x): return x+i". Executing either 
10 times creates 10 duplicate functions. The hypnotic effect of 'lambda' 
is that some do not immediately see the equivalence.

> The usual solution is to *not* use a closure:
>  >>> funcs = [lambda x, i=i: x+i for i in range(10)]
>  >>> funcs[0].__closure__ is None
> True
>  >>> funcs[0](42)
> 42
>  >>> funcs[9](42)
> 51

The explicit closure solution intended to replace "lambda x,i=i:x+i" is

 >>> def makef(j):
	return lambda x: x+j

 >>> funcs = [makef(i) for i in range(10)]
 >>> list(funcs[_](42) for _ in range(10))
[42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
 >>> funcs[0].__closure__
(<cell at 0x00FCB4D0: int object at 0x1E213910>,)
 >>> funcs[9].__closure__
(<cell at 0x00FE0750: int object at 0x1E2139A0>,)

We now have difference cells containing different ints. To get different 
functions from multiple compilations of one body we need either 
different defaults for pseudo-parameters or different closure cells. The 
rationale for adding the latter was partly to be an alternative to the 

Once closure cells were made writable with 'nonlocal', they gained 
additional uses, or rather, replaced the awkward hack of using mutable 
1-element lists as closure contents, with the one elements being the 
true desired content.

Terry Jan Reedy

More information about the Python-ideas mailing list