https://docs.python.org/3/reference/executionmodel.html#resolution-of-names的最后一段说
在名称解析的上下文中,类定义块和exec()和eval()的参数是特殊的。类定义是可以使用和定义名称的可执行语句。这些引用遵循通常的名称解析规则,但在全局命名空间中查找未绑定的局部变量。
引用文字的最后一句是什么意思?首先,我从中推断出以下代码将打印1
a = 1
def foo():
a = 2
def bar():
class Bar:
b = a
print(Bar.b)
bar()
foo()
但是我错了-由上面的代码组成的模块,在运行时会打印2
,即类定义中的名称a
,即使它未绑定在类定义块中,与文档所说的相反,它没有绑定在本地块的外部,也没有在全局名称空间中查找。
我尝试了下面描述的另一个代码段(使用del
语句,该语句是将变量绑定到其中的结构)
a = 1
def foo():
a = 2
def bar():
class Bar:
del a
print(Bar.b)
bar()
foo()
但是del
语句引发NameError: name 'a' is not defined
。
所以,我不明白,那句话是什么意思?
答案 0 :(得分:6)
如果名称绑定在块中,则除非声明为非本地或全局变量,否则它是该块的局部变量。
在您的第一个代码块中,a
没有绑定到class Bar
定义中的任何内容,因此它不是该块的局部变量。
绑定名称的一种方法是在赋值语句的左侧使用它。这是一个例子。
a = 1
def foo():
a = 2
class Bar:
b = a
a = 3
print(Bar.b)
foo()
结果:
1
这说明了“在全局名称空间中查找未绑定局部变量”的原理-b = a
使用全局a
的值,而不是局部区域a
的值到foo
。
在第二个示例中,a
被认为是class Bar
块的本地对象,因为“在del语句中出现的目标也被认为是绑定的”确定名称范围的目的。但是“在全局名称空间中查找未绑定的局部变量”并不重要,因为del
不需要查找名称的值即可解除绑定。
出于良好的考虑,我们可以通过实验确认del
语句向解释器发送信号,表明应将名称视为本地名称。
a = 1
def foo():
a = 2
class Bar:
print(a)
del a
foo()
结果:
1
Traceback (most recent call last):
File "C:\Users\Kevin\Desktop\test.py", line 7, in <module>
foo()
File "C:\Users\Kevin\Desktop\test.py", line 4, in foo
class Bar:
File "C:\Users\Kevin\Desktop\test.py", line 6, in Bar
del a
NameError: name 'a' is not defined
在这里我们看到print(a)
成功地查询了局部变量a
的值,然后在下一行它崩溃了,因为del
无法删除未绑定的局部变量。
答案 1 :(得分:1)
范围的局部变量是该范围中任何位置定义的任何名称。值得注意的是,变量本身是局部变量,而不是分配给它的值-局部变量可以在赋值之前或与赋值无关。
>>> def foo(): # new function scope
... a = 3 # local variable `a`
... b: int # local variable `b`
... c = 3 # local variable `c`
... del c
... print(x)
... x = 3 # local variable `x`
... foo()
UnboundLocalError: local variable 'x' referenced before assignment
未绑定局部变量就是这样的局部变量,未绑定任何值。在上面的示例中,b
,c
和x
中的所有一个都未绑定。
都不访问未绑定的局部变量。两者都查找名称a
,但从不为其分配名称。
在功能块中,引用未绑定的局部变量是错误,即UnboundLocalError
。该名称是否也包含在封闭范围内都没关系。
>>> x = 1
>>> def foo():
... b = x # local variable is looked up locally
... x = 2 # make `x` a local variable
... foo()
UnboundLocalError: local variable 'x' referenced before assignment
在 class块中,引用未绑定的局部变量将回退到全局范围中的查找。这可能成功也可能不会成功。
>>> x = 1
>>> class Foo:
... b = x # local variable is looked up locally *or globally*
... x = 2 # make `x` a local variable
... print(Foo.b, Foo.x)
1 2
>>> class Foo:
... b = y # local variable is looked up locally *or globally*
... y = 2 # make `y` a local variable
... print(Foo.b, Foo.y)
NameError: name 'y' is not defined
答案 2 :(得分:0)
我想我可以做个补充。
Python在执行函数主体之前会预先计算包含每个名称的框架。
这意味着这种现象:
In [1]: a = 1
In [2]: def test():
...: print(a)
...:
In [3]: test()
1
In [4]: def test():
...: print(a)
...: a = 1
...:
In [5]: test()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-5-fbd55f77ab7c> in <module>
----> 1 test()
<ipython-input-4-a08051373573> in test()
1 def test():
----> 2 print(a)
3 a = 1
4
UnboundLocalError: local variable 'a' referenced before assignment
In [6]:
错误local variable 'a' referenced before assignment
表示Python预计算函数test
的框架具有一个名为a
的局部变量,我们必须首先将一个对象分配给a
,然后对其进行引用以后。