闭包的变量作用域
def A():
b = True
def C():
b = False
C()
return b # True
因为C()里面的是局部变量,只能访问不能修改A()的变量。可以使用nolocal这个关键字,不过副作用很大,不建议使用。
def A():
b = True
def C():
nolocal b
b = False
C()
return b # True
迂回的实现方式就是使用list数据结构
def A():
b = [True]
def C():
b[0] = False
C()
return b[0] # False
闭包变量顺序
def a(x, y, a):
def b(z):
return x + y + a + z
return b
f1 = a(1, 2, 3)
print(f1.__closure__[0].cell_contents)
print(f1.__closure__[1].cell_contents)
print(f1.__closure__[2].cell_contents)
输出
3
1
2
原因:按照变量的名称排序a>x>y
修改闭包变量
问题如下:
有一函数a
def a(x):
def b(y):
return x + y
return b
执行
f1 = a(1)
f1(1) #返回2
问:如何在不对f1重新赋值的情况下,让f1(1)返回3?
在python3.7,可以直接修改
def a(x):
def b(y):
return x + y
return b
f1 = a(1)
print(f1(1)) #输出2
f1.__closure__[0].cell_contents = 2
print(f1(1)) #输出3
python3.7以前的版本会报错
attribute cell contents of cell objects is not writable
通过替换内存的实现
在google了解到一个ctypes库可以根据python对象id进行内存替换。
先简单说明一下closure是一个元组,元组里面都是cell对象,cell对象的cell_contents就是闭包函数里面变量的值。
我的思路是新建一个a(2),然后用a(2)的closure[0]替换a(1)的closure[0]。
代码如下
#coding: utf-8
import ctypes
def a(x):
def b(y):
return x + y
return b
f1 = a(1)
print(f1(1))
f2 = a(2)
size = int(f1.__closure__[0].__sizeof__())
ctypes.memmove(id(f1.__closure__[0]), id(f2.__closure__[0]), size)
print(f1(1))