【问题标题】:Local and global references with UnboundLocalErrorUnboundLocalError 的本地和全局引用
【发布时间】:2017-12-03 16:45:33
【问题描述】:

我不太明白为什么代码

def f():
    print(s)

s = "foo"
f()

运行得很好,但是

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

s = "foo"
f()

给我 UnboundLocalError。我知道我可以通过将 s 声明为函数内的全局变量或简单地将 s 一个参数传递给函数来解决此问题。

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

【问题讨论】:

  • 函数对象似乎知道所有这些东西。您可以使用f.__code__ 进行检查。它具有co_nlocalsco_varnames 等属性。

标签: python function global local


【解决方案1】:

其他答案侧重于实际方面,但并未真正回答您提出的问题。

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

nonlocalglobal 语句可以覆盖它。

【讨论】:

    【解决方案2】:

    是的,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试图在全局范围内找到它,但它不存在。

    【讨论】:

    • 在 bar 被声明之前,您没有引用它。你只是在定义一个函数! bar 将在运行时被引用,并且在函数 foo 的本地范围之前存在全局性!
    • 是的,您指的是全局名称栏。而且由于 Python 使用哈希表来恢复它的变量,它只记得在运行时它应该哈希 bar,并从全局范围内恢复相应的值。
    • @ElisByberi 我明白你的意思,我会澄清一下 Python 实际上并没有声明变量。
    • 你有点跑题了。再次查看问题。
    • 是的,你是对的......答案应该只是'是的,Python 提前恢复作用域中声明的变量以掩盖全局变量'
    猜你喜欢
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 2012-11-14
    • 2013-11-29
    相关资源
    最近更新 更多