Python 2.x中的nonlocal关键字

128 投票
10 回答
48838 浏览
提问于 2025-04-16 00:54

我正在尝试在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

撰写回答