Python 2.x中的nonlocal关键字
我正在尝试在Python 2.6中实现一个闭包,但我需要访问一个非局部变量,结果发现Python 2.x中似乎没有这个关键词。那在这些版本的Python中,应该怎么访问闭包里的非局部变量呢?
10 个回答
37
与字典相比,非局部类的结构更简单。我们可以修改一下 @ChrisB 的 示例:
def outer():
class context:
y = 0
def inner():
context.y += 1
return context.y
return inner
然后
f = outer()
assert f() == 1
assert f() == 2
assert f() == 3
assert f() == 4
每次调用 outer() 时,都会创建一个新的、独特的类,叫做 context(这不仅仅是创建一个新的实例)。这样就避免了 @Nathaniel 提到的关于共享上下文的警告。
g = outer()
assert g() == 1
assert g() == 2
assert f() == 5
39
下面的解决方案受到Elias Zamaria的回答的启发,但与那个回答不同的是,它能够正确处理外部函数的多次调用。这里提到的“变量”inner.y
是当前调用outer
时的局部变量。其实它并不是一个普通的变量,因为那样是不允许的,而是一个对象的属性(这个对象就是函数inner
本身)。虽然这样做看起来很丑陋(注意,属性只能在inner
函数定义之后创建),但似乎效果不错。
def outer():
def inner():
inner.y += 1
return inner.y
inner.y = 0
return inner
f = outer()
g = outer()
print(f(), f(), g(), f(), g()) #prints (1, 2, 1, 3, 2)
133
在Python 2.x中,内部函数可以读取外部变量的值,但不能重新绑定这些变量。这有点麻烦,不过我们可以找到解决办法。你只需要创建一个字典,把你的数据存储在字典里。内部函数是可以修改外部变量所指向的对象的。
下面是维基百科的一个例子:
def outer():
d = {'y' : 0}
def inner():
d['y'] += 1
return d['y']
return inner
f = outer()
print(f(), f(), f()) #prints 1 2 3