局部变量在赋值前引用" - 只有函数吗?
来看下面这段代码:
import something
def Foo():
something = something.SomeClass()
return something
…这显然不是有效的代码:
UnboundLocalError: local variable 'something' referenced before assignment
…因为局部变量 something
被创建了,但在评估 =
右边的内容之前并没有被赋值。(比如,可以参考这个相关回答的评论。)这让我觉得有点奇怪,不过好吧,我接受这个说法。那么,为什么下面的代码是有效的呢?
class Foo(object):
something = something.SomeClass()
我理解的是,class
定义内部基本上是一个作用域:
类的代码块会在一个新的执行框架中执行(参见命名和绑定部分),使用一个新创建的局部命名空间和原始的全局命名空间。
那么,为什么这段代码的行为和函数的行为不一样呢?
2 个回答
考虑下面这个例子,可能会帮助你更好地理解:
import datetime
class Foo(object):
datetime = datetime.datetime
>>> datetime
<module 'datetime' from '/usr/lib/python2.6/lib-dynload/datetime.so'>
>>> Foo.datetime
<type 'datetime.datetime'>
注意这一行 datetime = datetime.datetime
实际上是把值赋给了名字 Foo.datetime
,这和全局的 datetime
没有混淆(如果这段代码在函数里面就会有混淆)。
总的来说,因为类的定义会创建一个新的命名空间和新的作用域,所以你可以直接访问外部作用域中的名字,并且在本地作用域中给同样的名字赋值。
来自Python类文档的内容:
类的定义会在本地作用域中创建一个新的命名空间。
Python有一个特别的特点:如果没有使用全局声明,给变量赋值时总是会进入最内层的作用域。赋值并不是复制数据,而是将名字和对象绑定在一起。删除操作也是一样:使用del x语句会把x从本地作用域引用的命名空间中移除。实际上,所有引入新名字的操作都使用本地作用域:特别是,import语句和函数定义会在本地作用域中绑定模块或函数的名字。(全局声明可以用来指明某些变量是在全局作用域中。)
所以在一个函数(或作用域)中,赋值会创建一个本地的未绑定变量,这个变量在绑定之前就可以被访问。而在类的定义中,赋值会在该类的“命名空间”字典中创建一个条目,这样就可以将something
解析到外部命名空间(模块命名空间)。