python子类访问父类变量的类

python子类访问父类变量的类,python,subclass,class-variables,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, i

我惊讶地发现,子类的类变量无法访问父类的类变量,除非明确指出父类的类名:

>>> 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
>>A类(对象):
...     x=0
... 
>>>B(A)类:
...     y=x+1
... 
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第2行,在B中
名称错误:未定义名称“x”
>>>B(A)类:
...     y=A.x+1
... 
>>>B.x
0
>>>B.y
1.

为什么在定义B.y时,我必须参考A.x而不仅仅是x?这与我对实例变量的直觉相反,因为我可以在定义B之后引用B.x。

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


有关更多详细信息,请参见

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

任何时候需要不同的查找,都将使用限定的名称,而不是裸的名称。限定名称的功能要强大得多,因为查找始终可以委托给可以请求其属性的对象,而这些对象可以实现它们需要的任何查找规则。特别是,在类中的实例方法中,
self.x
是要求
self
对象查找属性名
'x'
——在该查找中,它可以委托给类,包括继承概念的实现(以及多重继承、方法解析顺序等)

类的主体(与类中定义的方法主体相反)在创建类对象或绑定其名称之前,作为
class
语句的一部分执行(特别是,在任何一个碱基被定义为碱基之前——尽管这个最新的细节在提到裸名时无论如何都不重要!)

因此,在您的示例中,在类
B
中,使用通用规则查找barename
x
——它是本地绑定的名称吗?如果不是,它是否绑定在嵌套此作用域的任何外部函数中?如果不是,它是绑定为全局还是内置的?如果没有上述规则,使用所讨论的barename当然会导致名称错误激动

由于您需要一个不同于通用的裸名查找规则的查找序列,因此显然您需要使用一个限定名,而不是裸名;片刻的反思将清楚地表明“一个显而易见的选择”用于您的目的的限定名称必须是
a.x
——因为您希望在那里查找它(毕竟,在那一点上,基类还没有被记录到任何地方……元类(通常是
类型
)将在类主体执行完毕后调用基类绑定,作为其工作的一部分!-)

有些人对查找裸名的其他“神奇”规则如此痴迷,以至于他们无法忍受Python的这一方面(我相信,最初是受到Modula-3的启发,Modula-3是一种鲜为人知的语言,在理论家圈子里得到了很好的考虑;-)--必须以一种方法编写
self.x
,以指定必须在
self
上查找
x
,而不是使用通用的裸名规则,例如,这会让这些人变得暴躁


我,我喜欢裸名查找规则的简单性和通用性,我喜欢在任何时候使用限定名而不是裸名来进行任何其他形式的查找……但是,我疯狂地爱上Python并不是什么秘密(我有自己的抱怨——例如,
global x
,因为一句话总是让我毛骨悚然,我更愿意写
global.x
,也就是说,
global
是“当前正在执行的模块”的内置名称……我确实喜欢限定名称!-),是吗?-)

但是如果你的子类有一系列超类呢?那么限定名要求你知道类变量是在哪个超类中设置的。当然,我可以看到这样的情况,即这种要求会使事情变得更安全,但也有一些情况是限制性的。对于类变量来说,有一个与“super”等价的名称似乎很好。Howe无论如何,在我看来,使用类定义主体中括号中的类“作为参数传递”是很自然的。例如:
class B(super=a):y=super.x+1
(我知道
super
函数的魔力,我被它吓坏了。)