UnboundLocalError的本地和全局引用

时间:2017-12-03 16:45:34

标签: python function global local

我不太明白为什么代码

def f():
    print(s)

s = "foo"
f()

运行得非常好,但

def f():
    print(s)
    s = "bar"

s = "foo"
f()

给我UnboundLocalError。我知道我可以通过将 s 声明为函数内部的全局变量或者只是将 s 一个参数传递给函数来解决这个问题。

我仍然不明白python如何知道在执行该行之前是否在函数内部引用了s?当函数被读入全局框架时,python是否会创建所有局部变量引用的某种列表?

2 个答案:

答案 0 :(得分:1)

是的,Python将预先恢复在本地范围内声明的所有变量。这些将掩盖全球变量。

所以在你的代码中:

def f():
    print(s)

s = "foo"
f()

Python在本地范围内未找到s,因此它尝试从全局范围中恢复它并找到"foo"

现在在另一种情况下会发生以下情况:

def f():
    print(s)
    s = "bar

s = "foo"
f()

Python知道s是一个局部变量,因为它在运行时之前进行了预测,但是在运行时它还没有被分配,所以它被引发和异常。

请注意,Python甚至可以让您引用尚未在任何地方声明的变量。如果你这样做:

def foo():
    return x
f()

你会得到一个NameError,因为Python在没有找到x作为局部变量时会记得在运行时它应该寻找一个名为x的全局变量然后如果它不存在则失败。

所以UnboundLocalError意味着变量最终可能在范围内声明但尚未声明。另一方面,NameError意味着变量永远不会在本地范围内声明,因此Python试图在全局范围内找到它,但它不存在。

答案 1 :(得分:1)

其他答案都集中在这方面的实际方面,但实际上并没有回答你提出的问题。

是的,Python编译器跟踪在编译代码块时分配的变量(例如在def中)。如果在块中指定了名称,则编译器将其标记为本地。请查看function.__code__.co_varnames以查看编译器已识别的变量。

nonlocalglobal语句可以覆盖此内容。