Is there a way to change the closure of a python function?

Ian Kelly ian.g.kelly at gmail.com
Tue Sep 27 17:56:39 EDT 2016


On Tue, Sep 27, 2016 at 3:19 PM, Terry Reedy <tjreedy at udel.edu> wrote:
> On 9/27/2016 11:01 AM, Chris Angelico wrote:
>>
>> On Wed, Sep 28, 2016 at 12:01 AM, Peng Yu <pengyu.ut at gmail.com> wrote:
>>>
>>> Hi, In many other functional language, one can change the closure of a
>>> function. Is it possible in python?
>>>
>>> http://ynniv.com/blog/2007/08/closures-in-python.html
>>>
>>
>> From the blog post:
>>
>> """In some languages, the variable bindings contained in a closure
>> behave just like any other variables. Alas, in python they are
>> read-only."""
>>
>> This is not true, at least as of Python 3.
>>
>> def makeInc(x):
>>   def inc(y, moreinc=0):
>>      # x is "closed" in the definition of inc
>>      nonlocal x
>>      x += moreinc
>>      return y + x
>>   return inc
>
>
> The value of the cell variable is writable from within the body of the
> closure function if declared nonlocal, but not otherwise, and not from
> without.  The latter may be what Peng meant by 'change' and the blogger by
> 'read-only'.
>
> def makeInc(x):
>   def inc(y, moreinc=0):
>      # x is "closed" in the definition of inc
>      nonlocal x
>      x += moreinc
>      return y + x
>   return inc
>
> f = makeInc(23)
> fclose = f.__closure__  # a tuple of 'cells'
> fcell = fclose[0]
>
> print(dir(fcell))
> # ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__',
> # '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
> # '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__',
> # '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
> # '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
> # Note: no mutation method
>
> print('cell content = ', fcell.cell_contents)
> # cell content = 23
>
> fcell.cell_contents = 32
> ### results in
> Traceback (most recent call last):
>   File "F:\Python\mypy\tem.py", line 14, in <module>
>     fcell.cell_contents = 32
> AttributeError: attribute 'cell_contents' of 'cell' objects is not writable
> # unless one does so from within the closure body with 'nonlocal'
> declaration.  I presume there is a special byte code for this.

You could, however, put a mutable object in the cell variable and then
modify it from without. E.g.:

def makeInc(x):
  x = [x]
  def inc(y, moreinc=0):
    x[0] += moreinc
    return y + x[0]
  return inc

f = makeInc(23)
fcell = f.__closure__[0]
fcell.cell_contents
# [23]
fcell.cell_contents[0] = 42
f(0)
# 42



More information about the Python-list mailing list