在Python中修改闭包的绑定变量
有没有办法修改闭包中某个变量的绑定值?看看这个例子,更好地理解它在Python中修改闭包的绑定变量,python,functional-programming,closures,Python,Functional Programming,Closures,有没有办法修改闭包中某个变量的绑定值?看看这个例子,更好地理解它 def foo(): var_a = 2 var_b = 3 def _closure(x): return var_a + var_b + x return _closure localClosure = foo() # Local closure is now "return 2 + 3 + x" a = localClosure(1) # 2 + 3 + 1 == 6
def foo():
var_a = 2
var_b = 3
def _closure(x):
return var_a + var_b + x
return _closure
localClosure = foo()
# Local closure is now "return 2 + 3 + x"
a = localClosure(1) # 2 + 3 + 1 == 6
# DO SOME MAGIC HERE TO TURN "var_a" of the closure into 0
# ...but what magic? Is this even possible?
# Local closure is now "return 0 + 3 + x"
b = localClosure(1) # 0 + 3 +1 == 4
为什么不使用函数foo的var_a和var_b参数呢
def foo(var_a = 2, var_b = 3):
def _closure(x):
return var_a + var_b + x
return _closure
localClosure = foo() # uses default arguments 2, 3
print localClosure(1) # 2 + 3 + 1 = 6
localClosure = foo(0, 3)
print localClosure(1) # 0 + 3 + 1 = 4
我认为在Python中没有任何方法可以做到这一点。定义闭包后,将捕获封闭范围内变量的当前状态,并且不再具有可直接引用的名称(从闭包外部)。如果再次调用
foo()
,则新闭包将具有与封闭范围不同的一组变量
在您的简单示例中,您最好使用一个类:
class foo:
def __init__(self):
self.var_a = 2
self.var_b = 3
def __call__(self, x):
return self.var_a + self.var_b + x
localClosure = foo()
# Local closure is now "return 2 + 3 + x"
a = localClosure(1) # 2 + 3 + 1 == 6
# DO SOME MAGIC HERE TO TURN "var_a" of the closure into 0
# ...but what magic? Is this even possible?
localClosure.var_a = 0
# Local closure is now "return 0 + 3 + x"
b = localClosure(1) # 0 + 3 +1 == 4
如果您使用这种技术,我将不再使用名称
localClosure
,因为它实际上不再是一个闭包。但是,它的工作原理与一个相同。我找到了Greg的另一个答案,稍微不那么详细,因为它使用Python2.1的自定义函数属性(可以从自己的函数内部方便地访问这些属性)
我想我会把它贴出来。无论如何,干杯。这在python 3中是完全可能的,多亏了的魔力
我们已经做了以下工作。我认为它比这里的其他解决方案更简单
class State:
pass
def foo():
st = State()
st.var_a = 2
st.var_b = 3
def _closure(x):
return st.var_a + st.var_b + x
def _set_a(a):
st.var_a = a
return _closure, _set_a
localClosure, localSetA = foo()
# Local closure is now "return 2 + 3 + x"
a = localClosure(1) # 2 + 3 + 1 == 6
# DO SOME MAGIC HERE TO TURN "var_a" of the closure into 0
localSetA(0)
# Local closure is now "return 0 + 3 + x"
b = localClosure(1) # 0 + 3 +1 == 4
print a, b
我通过使用一个项目列表而不是一个普通变量来解决类似的限制。这很难看,但它可以工作,因为解释器不会将修改列表项视为绑定操作 例如:
def my_function()
max_value = [0]
def callback (data)
if (data.val > max_value[0]):
max_value[0] = data.val
# more code here
# . . .
results = some_function (callback)
store_max (max_value[0])
与要求的略有不同,但您可以:
def f():
a = 1
b = 2
def g(x, a=a, b=b):
return a + b + x
return g
h = f()
print(h(0))
print(h(0,2,3))
print(h(0))
并将闭包设置为默认值,以便在需要时覆盖 也许还有更进一步的方法(即使对我的提议来说似乎已经晚了几年:-)
在我看来,提出的课堂解决方案更容易阅读。但是,如果您试图修改装饰器中的自由变量,此解决方案可能会派上用场:与基于类的解决方案相比,使用functools.wrapps来保存装饰函数的元数据更容易。这并不能完全解决我的问题,因为我需要修改已经创建的闭包的值。也就是说,您的答案要求我每次需要更改绑定变量时都创建一个新的闭包。+1:第一类对象,而不是闭包。闭包是一种特殊的非对象事物。对象比闭包更清晰、更容易处理。事实上有一种方法。非本地的。看我的帖子。我也会的,这肯定比另一种方式好。我的意思是,默认情况下,它应该是nonlocalDoh!我本想说我不会的。在我看来,它仍然很怪异。关于更改值的可选参数的整个位。整件事应该是一门课。但无论如何,我离题了。
def foo():
var_b = 3
def _closure(x):
return _closure.var_a + var_b + x
_closure.func_dict['var_a'] = 2
return _closure
localClosure = foo()
# Local closure is now "return 2 + 3 + x"
a = localClosure(1) # 2 + 3 + 1 == 6
# DO SOME MAGIC HERE TO TURN "var_a" of the closure into 0
# ...but what magic? Is this even possible?
# apparently, it is
localClosure.var_a = 0
# Local closure is now "return 0 + 3 + x"
b = localClosure(1) # 0 + 3 +1 == 4
def foo():
var_a = 2
var_b = 3
def _closure(x):
return var_a + var_b + x
return _closure
def bar():
var_a = [2]
var_b = [3]
def _closure(x):
return var_a[0] + var_b[0] + x
def _magic(y):
var_a[0] = y
return _closure, _magic
localClosureFoo = foo()
a = localClosureFoo(1)
print a
localClosureBar, localClosureBarMAGIC = bar()
b = localClosureBar(1)
print b
localClosureBarMAGIC(0)
b = localClosureBar(1)
print b
def f():
a = 1
b = 2
def g(x, a=a, b=b):
return a + b + x
return g
h = f()
print(h(0))
print(h(0,2,3))
print(h(0))
def foo():
def _closure(x):
return _closure.var_a + _closure.var_b + x
_closure.var_a = 2
_closure.var_b = 3
return _closure
localClosure = foo()
# Local closure is now "return 2 + 3 + x"
a = localClosure(1) # 2 + 3 + 1 == 6
print(a)
# DO SOME MAGIC HERE TO TURN "var_a" of the closure into 0
# ...but what magic? Is this even possible?
localClosure.var_a = 0
# Local closure is now "return 0 + 3 + x"
b = localClosure(1) # 0 + 3 +1 == 4
print(b)