编辑:看起来这是一个非常古老的“bug”,或者实际上是一个特性。例如,见this mail
我试图理解Python的作用域规则。更确切地说,我以为我能理解它们,但后来我发现了这个代码here:
x = "xtop"
y = "ytop"
def func():
x = "xlocal"
y = "ylocal"
class C:
print(x)
print(y)
y = 1
func()
在python3.4中,输出是:
^{pr2}$如果我用一个函数替换内部类,那么它合理地给出UnboundLocalError
。你能解释一下它为什么对类表现出这种奇怪的方式吗?为什么选择范围规则?在
首先关注函数内函数的闭包情况:
注意被注释掉的
global
在inner
中,如果您运行这个,它将复制您得到的UnboundLocalError
。为什么?在跑dis.dis公司上面写着:
^{pr2}$注意}
x
与func
内部y
的不同访问模式。在inner
中使用y='inner y'
创建了{现在取消对}
inner
内部的global y
的注释。现在,您已经明确地创建了y
作为顶级全球版本,直到您辞去{如果
global
未注释,则打印:您可以通过以下方式获得更合理的结果:
印刷品:
闭包类的分析由于实例和类变量以及裸类(没有实例)执行的时间和时间而变得复杂。在
底线是一样的:如果你引用了本地命名空间之外的一个名称,然后在本地分配给同一个名称,你会得到一个令人惊讶的结果。在
“fix”是相同的:使用global关键字:
印刷品:
您可以在PEP 3104中阅读有关Python3范围规则的更多信息
TL;DR:这种行为从python2.1PEP 227: Nested Scopes就已经存在了,并且在那时就已经知道了。如果一个名称在类主体中被赋值(比如
y
),那么它就被认为是一个局部/全局变量;如果它没有被赋值给(x
),那么它也可能指向一个闭包单元。词法变量不会作为类主体的局部/全局名称显示。在在Python3.4上,
dis.dis(func)
显示了以下内容:}。类主体是函数
^{pr2}$LOAD_BUILD_CLASS
在堆栈上加载builtins.__build_class__
;这是用参数__build_class__(func, name)
调用的;其中func
是类主体,name
是{func
的常量#3:在类主体中,);而{}用于从局部变量加载值,然后从全局加载值。然而,闭合单元既不显示为局部的,也不显示为全局的。在
x
是用LOAD_CLASSDEREF
(15)访问的,而y
是用LOAD_NAME
(25)加载的。LOAD_CLASSDEREF
是一个python3.4+操作码,用于从类主体内的闭包单元加载值(在以前的版本中,使用了泛型的^{现在,由于名称
y
存储在类主体(35)中,因此它一直被用作本地/全局名称而不是闭包单元。 闭包单元不显示为类主体的局部变量。在这种行为是正确的ever since implementing PEP 227 - nested scopes。当时BDFL表示,这不应该是固定的,因此这13年来一直如此。在
自PEP 227以来的唯一变化是在Python3中添加了
nonlocal
;如果在类主体中使用它,那么类主体可以设置包含范围内单元格的值:现在的输出是
也就是说,
print(y)
读取包含范围的单元格y
的值,y = 1
设置该单元格中的值;在这种情况下,没有为类C
创建属性。在相关问题 更多 >
编程相关推荐