用两个词来说,示例5和示例6之间的区别在于,示例5中的变量
x也被分配到相同的范围内,而示例6中没有。这触发了可以由历史原因理解的差异。
这引发了UnboundLocalError:
x = "foo"def f(): print x x = 5f()
而不是打印“
foo”。即使一开始看起来很奇怪,这还是有道理的:函数f()在
x本地定义了变量,即使它在打印之后也是如此,因此
x在同一函数中对它的任何引用都必须是对该局部变量的引用。至少这是有道理的,如果您错误地在本地重用了全局变量的名称,并试图同时使用全局变量和局部变量,则可以避免意外的意外。这是一个好主意,因为这意味着我们可以静态地知道,只要看一眼变量,
这 意味着变量。例如,我们知道这里
print x引用了局部变量(因此可能引发UnboundLocalError):
x = "foo"def f(): if some_condition: x = 42 print xf()
现在,此规则不适用于类级范围:在那里,我们希望表达式
x =x能够正常工作,将全局变量捕获
x到类级范围中。这意味着类级别的作用域不遵循上面的基本规则:例如,我们不知道
x该作用域中是指某个外部变量还是本地定义的
x-–:
class X: x = x # we want to read the global x and assign it locally bar = x # but here we want to read the local x of the previous lineclass Y: if some_condition: x = 42 print x # may refer to either the local x, or some global xclass Z: for i in range(2): print x # prints the global x the 1st time, and 42 the 2nd time x = 42
因此,在类范围内,使用了不同的规则:通常会引发UnboundLocalError的地方—仅在这种情况下—
而是在模块全局变量中查找。仅此而已:它不遵循嵌套作用域链。
为什么不?我实际上怀疑有一个更好的解释是“出于历史原因”。用更专业的术语来说,它可以认为该变量
x既在类作用域中本地定义(因为已被分配给它), 又
应从父作用域作为词法嵌套变量传递(因为已被读取)。可以通过使用与
LOAD_NAME在本地作用域中查找的字节码不同的字节码来实现它,如果未找到,则退回到使用嵌套作用域的引用。
编辑:
感谢wilberforce对http://bugs.python.org/issue532860的引用。如果我们认为毕竟应该修复该问题,那么我们可能有机会用提议的新字节码重新进行一些讨论(错误报告考虑终止对它的支持,
x= x但由于担心破坏太多现有代码而被关闭;相反,我是我建议这里将
x = x在更多情况下进行工作)。否则我可能会错过另一个要点…
EDIT2:
似乎CPython在当前的3.4主干中确实做到了这一点:http :
//bugs.python.org/issue17853 …
…还是不?他们介绍字节码的原因略有不同,因此没有系统地使用它。



