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