46

在以下 Python 代码中,我得到一个UnboundLocalError. 据我了解,局部函数共享包含函数的局部变量,但这里似乎并非如此。我承认a在这种情况下这是一个不可变的价值,但这不应该是一个问题。

def outer():
    a = 0
    def inner():
        a += 1
    inner()
outer()

似乎内部函数已收到父函数中所有引用的副本,因为UnboundLocalError如果 的值a被包装在可变类型中,我不会得到异常。

有人能够澄清这里的行为,并指向我相应的 Python 文档吗?

4

3 回答 3

38

我相信您将其视为“可变性”问题是正确的。虽然您发布的代码确实会引发“UnboundLocalError”,但以下代码不会:

def outer():
    a = 0
    def inner():
        print a
    inner()
outer()

Python 不允许您在内部范围内从外部范围重新分配变量的值(除非您使用关键字“global”,在这种情况下不适用)。

查看此 Python 2.6.2 文档中“类”文档的底部部分:

9.2. Python 范围和命名空间

[…] 如果一个名称被声明为全局的,那么所有的引用和赋值都会直接进入包含模块全局名称的中间作用域。否则,在最内层范围之外找到的所有变量都是只读的(尝试写入此类变量只会在最内层范围内创建一个新的局部变量,而保持相同名称的外部变量不变)。

您的“UnboundLocalError”是因为您的函数实际上是在声明一个名为“a”的新变量,然后立即尝试对其执行“+=”操作,但这会失败,因为“a”还没有值。(将“a+=1”视为“a = a+1”,如果“a”未定义,您可以看到问题)。

通常,如果您要修改“a”,人们通常绕过它的方法是使用可变类型来传递“a”(例如列表或字典)。您可以通过可变类型的内容修改“a”(正如您在使用此设置进行测试时可能注意到的那样)。

希望有帮助!

于 2009-09-12T04:54:30.797 回答
19

您应该将您的变量指定为 nonlocal 以在关闭时保留它的状态,因此定义应该是这样的

def outer():
    a = 0
    def inner():
        nonlocal a
        a += 1
    inner()
于 2013-03-11T08:41:38.220 回答
11

尝试将变量绑定为参数。

def outer():
    a = 0
    def inner(a=a):
        a += 1

    inner()

outer()

我会尝试挖掘适当的文件。

编辑

由于您希望内部函数对外部范围产生副作用,因此您需要使用可变数据类型,如列表。整数和字符串是不可变的。

def outer():
    a = [0]
    def inner():
        a[0] += 1
    inner()
    print a[0]
outer()
于 2009-09-12T04:55:11.733 回答