Python和闭变量

Python和闭变量,python,closures,python-2.x,Python,Closures,Python 2.x,请查看以下代码: def closure(): value = False def method_1(): value = True def method_2(): print 'value is:', value method_1() method_2() closure() 我希望它能打印“Value is:True”,但事实并非如此。为什么会这样?解决方案是什么?之所以会这样,是因为方法\u 1有自己的局部范

请查看以下代码:

def closure():
    value = False

    def method_1():
        value = True

    def method_2():
        print 'value is:', value

    method_1()
    method_2()

closure()

我希望它能打印“Value is:True”,但事实并非如此。为什么会这样?解决方案是什么?

之所以会这样,是因为
方法\u 1
有自己的局部范围,可以在其中声明变量。Python看到
value=True
并认为您正在创建一个名为
value
的新变量,它是
method\u 1
的本地变量

Python这样做的原因是为了避免内部函数的变量污染外部作用域的局部变量。(您不希望常规模块级函数中的赋值导致创建全局变量!)

如果您没有分配给
,那么Python将搜索外部作用域以查找变量(因此读取变量的效果与预期一样,正如您的
方法_2
所示)

解决这一问题的一种方法是使用可变对象而不是assignment:

result = { 'value': False }

def method_1():
    result['value'] = True
在Python3中,添加了(另请参见)用于此场景:

def method_1():
    nonlocal value
    value = True    # Works as expected -- assigns to `value` from outer scope

method_1
中,Python(相当明智地!)假设
value
是一个局部变量。每当在函数中指定变量名时,都假定该变量名是一个新的局部变量。如果您希望它是全局的,那么您必须将其声明为
global
,如果您希望它是“非本地的”,在Python 3中,您可以将其声明为
nonlocal
,但在Python 2中,您必须做一些更难看的事情:将值存储在容器中。这避免了必须重新分配变量名,从而避免了范围模糊

def method_1_global():
    global value
    value = True

def method_1_nonlocal_P3():
    nonlocal value
    value = True

value = [False]
def method_1_nonlocal_P2():
    value[0] = True

分配给变量时,它假定该变量属于局部范围。因此
方法1中的
不是
闭包中的

如果您想在Python3上实现这一点,请在
方法_1
中添加一行:
非局部值

在Python 2上

def closure():
    value = [False]

    def method_1():
        value[0] = True

    def method_2():
        print 'value is:', value

    method_1()
    method_2()

closure()

这是一种可能的解决方法。

这是因为您实际上没有修改closed over变量-您正在用一个同名的新变量来屏蔽它。在Python2.x中没有简单的方法可以解决这个问题,这就是为什么Python3中添加了
nonlocal
关键字的原因


不过,这可以通过使用列表和字典等可变类型来解决。有一个。

为了避免这种情况,您可以使用列表

value = [False]

def method_1():
    value[0] = True

Python现在做的是在更高级别的范围中搜索,因为值在局部变量中不可用。由于value是一个列表,Python将其作为相对于*method_1*的全局变量引用,因此可以将value视为一个列表。

请注意,使用
global
时,它不再是闭包的一部分,可能会在程序中的其他地方出错。@agf--确实如此;我只是试图用尽可能一般的方式解释范围规则。这篇文章是一个完美的例子,说明为什么五分钟的自由编辑有时是不好的。