python子类访问父类的变量

时间:2010-09-06 01:34:42

标签: python subclass class-variables

我很惊讶地发现子类的类变量无法访问父类的类变量而没有明确指出父类的类名:

>>> 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 个答案:

答案 0 :(得分:48)

Python的裸名称范围规则非常简单明了:首先是本地名称空间,然后是(如果有的话)当前嵌套的外部函数,然后是全局变量,最后是内置函数。这就是查找裸名时所发生的一切,并且不需要记忆或应用任何复杂的规则(也不需要Python编译器来执行更复杂的规则)。

只要您想要不同的查询,您就会使用合格的名称,而不是名称。限定名称的功能非常强大,因为查找始终可以委托给可以请求其属性的对象,并且这些对象可以实现他们需要的任何查找规则。特别是,在类中的实例方法中,self.x 方式,要求self对象查找属性名称'x' - 并且查找它可以委托给类,包括继承概念的实现(以及多重继承,方法解析顺序等)。

类的 body (与类中定义的方法的主体相对)作为class语句的一部分执行,之前创建了类对象或者绑定了它的名称(特别是在任何基础被定义为基础之前 - 尽管这个最新细节在引用裸名时也无关紧要! - 。)。

因此,在您的示例中,在类B中,使用通用规则查找裸名x - 它是否是本地绑定的名称?如果不是,它是否绑定在嵌套此范围的任何外部函数中?如果不是,它是绑定为全局还是内置?如果不是上述情况,使用当前的裸名称会导致名称错误异常。

由于您希望查找序列不同于普遍强制执行的裸名查找规则,因此显然您需要使用限定名称,而不是名字;而片刻的反思将清楚地表明,为您的目的使用的合格名称的“一个显而易见的选择”必须是A.x - 因为那是您想要它被查找的地方(这个基点还没有被记录在那个之后,毕竟......它将是元类,通常是type,它将作为其一部分进行碱基结合在类主体完成执行后调用时的作业! - )。

有些人如此敏锐地依赖其他“魔法”规则查找裸名,他们无法忍受Python的这一方面(我相信,最初的灵感来自Modula-3,一种鲜为人知的语言,非常好在理论家的圈子中考虑;-) - 必须在方法中编写self.x来指定x必须在self上查找,而不是使用通用的裸名称规则,例如,推动这些人惨不忍睹。

我,我喜欢裸名查找规则的简单性和普遍性,我喜欢在任何时候想要任何其他形式的查找时使用限定名称而不是裸名...但是,它不是一个秘密,我疯狂地爱上了Python(我有自己的抱怨 - 例如,global x作为一个声明总是让我的皮肤爬行,我宁愿写global.x,即,让global成为“当前正在执行的模块”的内置名称...我喜欢合格的名字! - ),是吗? - )

答案 1 :(得分:26)

在Python中,类的主体在创建类之前在其自己的命名空间中执行(之后,该命名空间的成员将成为该类的成员)。因此,当解释器达到y = x + 1时,B类在那时尚不存在,因此没有父级。

有关详细信息,请参阅http://docs.python.org/reference/compound_stmts.html#class-definitions