Python有一条非常简单的规则,即将作用域中的每个名称分配给一个类别:本地,封闭式或全局/内置。
(当然,CPython通过使用FAST局部变量,DEREF闭合单元以及NAME或GLOBAL查找来实现该规则。)
更改后的规则对于简单的情况确实很有意义,但是很容易提出模棱两可的情况(至少对于人类读者而言,如果不是编译器)。例如:
def outer(): var = 1 def inner(): if spam: var = 1 var += 1 return var return inner
这样
var += 1做
LOAD_DEREF或
LOAD_FAST吗?直到我们知道
spam运行时的值,我们才能知道。这意味着我们不能编译函数体。
即使您可以提出一个更有意义的复杂规则,但该规则的内在优点也很简单。除了易于实现(因此易于调试,优化等)之外,其他人也很容易理解。当您获得时
UnboundLocalError,任何中级Python程序员都知道如何在脑海中遍历该规则并找出出了什么问题。
同时,请注意,当在现实生活中的代码中出现这种情况时,有很简单的方法可以明确地解决它。例如:
def inner(): lvar = var + 1 return lvar
您想加载闭包变量,并分配给局部变量。他们没有理由需要使用相同的名称。实际上,即使使用新规则,使用相同的名称也会产生误导,这实际上向读者暗示您正在修改闭包变量,而实际上并非如此。因此,只要给他们起不同的名字,问题就解决了。
这仍然适用于非本地分配:
def inner(): nonlocal var if spam: var = 1 lvar = var + 1 return lvar
或者,当然,还有一些技巧,例如使用参数默认值来创建以闭包变量的副本开头的本地:
def inner(var=var): var += 1 return var



