类对象具有__bases__
(和__base__
)属性:
>>> class Foo(object):
... pass
...
>>> Foo.__bases__
(<class 'object'>,)
可悲的是,这些属性无法在类主体中访问,这对于访问父类属性非常方便,而无需对名称进行硬编码:
class Foo:
cls_attr = 3
class Bar(Foo):
cls_attr = __base__.cls_attr + 2
# throws NameError: name '__base__' is not defined
为什么在类主体中无法访问
__bases__
和__base__
?(要清楚,我要问的是这是一个有意识的设计决定。我不是在问实现;我知道
__bases__
是type
中的一个描述符,并且只有在类对象被创建后才能访问该描述符。我想知道为什么python不会在类主体中将__bases__
创建为局部变量。) 最佳答案
如您所知,class
通常是type.__new__()
的快捷方式-当运行时命中class
语句时,它将在class
主体的顶层执行所有语句,在专用的命名空间dict中收集所有结果绑定(bind),并使用具体的元类调用type()
,类名称,基类和 namespace dict,并将结果的类对象绑定(bind)到封闭范围内的类名称(通常但不一定是模块的顶级 namespace )。
这里的重点是,构建类对象并允许自定义类对象的创建是元类的责任,元类必须可以自由地对其参数进行任何操作。大多数情况下,自定义元类将主要对attrs
dict起作用,但是它也必须能够与bases
参数混淆。现在,由于仅在执行了类主体语句之后才调用元类,因此运行时无法可靠地在类主体范围中公开bases
,因为这些基数随后可以由元类进行修改。
这里还有更多的哲学方面的考虑,特别是wrt/explicit和隐式,并且如shx2所提到的,Python设计人员试图避免魔术变量突然出现。实际上,确实有几个实现变量(__module__
和py3中的__qualname__
)在类主体 namespace 中“自动”定义,但它们只是名称,主要用于为开发人员提供其他调试/检查信息,并且绝对没有影响。在类对象的创建上,也不在其属性,行为和其他方面。
与Python一样,您必须考虑整个上下文(执行模型,对象模型,不同部分如何协同工作等)才能真正理解设计选择。您是否同意整个设计和哲学是另一个争论(并且不属于此处),但是您可以肯定的是,这些选择是的“有意识的设计决策”。
关于python - 为什么在类主体中无法访问__base__?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56321582/