Python中的局部函数

51 投票
3 回答
57309 浏览
提问于 2025-04-15 14:16

在下面的Python代码中,我遇到了一个UnboundLocalError错误。我的理解是,内部函数可以使用外部函数的局部变量,但在这里似乎并不是这样。我知道在这个情况下,a是一个不可变的值,但这应该不是问题。

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

看起来内部函数得到了外部函数所有引用的副本,因为如果a的值被放在一个可变类型中,我就不会遇到UnboundLocalError这个错误。

有没有人能解释一下这里的行为,并指引我去查阅相关的Python文档?

3 个回答

10

试着把这个变量当作一个参数来绑定。

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()
24

你应该把你的变量声明为非局部变量,这样才能在闭包中保持它的状态。定义应该像这样:

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

我觉得你说得对,这确实是个“可变性”的问题。虽然你发的代码会出现“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”(你可能在测试这个设置时注意到了这一点)。

希望这能帮到你!

撰写回答