Python子类访问父类的类变量
我很惊讶地发现,子类的类变量不能直接访问父类的类变量,必须明确写出父类的名字:
>>> class A(object):
... x = 0
...
>>> class B(A):
... y = x+1
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in B
NameError: name 'x' is not defined
>>> class B(A):
... y = A.x + 1
...
>>> B.x
0
>>> B.y
1
为什么在定义 B.y 的时候,我必须提到 A.x,而不能直接用 x 呢?这和我对实例变量的理解相反,因为在 B 定义之后,我可以直接用 B.x。
2 个回答
Python中关于变量名称的作用域规则非常简单明了:首先查找局部命名空间,然后是当前函数外层的函数(如果有的话),接着是全局变量,最后是内置变量。查找变量名称时就只会按照这个顺序进行,没有必要记住或应用任何复杂的规则(Python编译器也不需要强制执行更复杂的规则)。
每当你想要不同的查找方式时,你就需要使用一个合格的名称,而不是裸名称。合格的名称功能更强大,因为查找可以委托给可以请求属性的对象,而这些对象可以实现它们需要的任何查找规则。特别是在类中的实例方法里,self.x
就是请求self
对象查找属性名称'x'
的方式——在这个查找过程中,它可以委托给类,包括继承的实现(还有多重继承、方法解析顺序等等)。
类的主体(与类中定义的方法的主体不同)在class
语句执行时就会运行,在类对象创建或其名称绑定之前(特别是在任何基类被定义之前——不过这个细节在提到裸名称时其实并不重要!)。
所以,在你的例子中,在类B
里,裸名称x
的查找是按照通用规则进行的——它是局部绑定的吗?如果不是,那它在任何外层函数中有绑定吗?如果也没有,那它是全局变量还是内置变量?如果以上都没有,使用这个裸名称当然会导致名称错误异常。
因为你想要的查找顺序与裸名称查找规则不一样,所以显然你需要使用合格的名称,而不是裸名称;稍微想一下就会发现,适合你目的的合格名称显然是A.x
——因为这正是你想要查找的地方(毕竟在那时基类还没有被记录下来... 通常是元类type
会在类主体执行完后负责绑定基类!)。
有些人对其他“神奇”的裸名称查找规则非常执着,以至于无法接受Python的这一点(我相信这最初是受到Modula-3的启发,这是一种在理论界备受推崇的小众语言;-)——例如,在方法中写self.x
来指定x
必须在self
上查找,而不是使用通用的裸名称规则,这让这些人感到非常困扰。
而我则喜欢裸名称查找规则的简单和通用,任何时候我想要其他形式的查找时,我都喜欢使用合格的名称... 不过,我对Python的热爱可不是秘密(我也有自己的抱怨——例如,global x
这个语句总让我感到不适,我更希望写成global.x
,也就是把global
当作“当前执行模块”的内置名称... 我确实喜欢合格的名称!),对吧?
在Python中,一个类的内容会在它被创建之前,在自己的命名空间中执行。简单来说,就是在类真正形成之前,里面的代码就已经开始运行了。等到类创建好后,这些代码里的成员就变成了这个类的成员。所以,当解释器执行到y = x + 1这行代码时,类B还没有被创建出来,因此它没有父类。
想了解更多细节,可以查看这个链接:http://docs.python.org/reference/compound_stmts.html#class-definitions