Class对象具有__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__
创建为局部变量。)
答案 0 :(得分:6)
我想知道为什么python不在类主体中创建
__bases__
作为局部变量
如您所知,class
主要是type.__new__()
的快捷方式-当运行时命中class
语句时,它将在{{1}的顶层执行所有语句}主体,在专用命名空间dict中收集所有结果绑定,使用具体的元类,类名,基类和命名空间dict调用class
,并将结果类对象绑定到封闭范围内的类名(通常但不一定是模块的顶级名称空间)。
这里的重点是,建立类对象并允许自定义类对象的创建是元类的责任,元类必须可以自由地对其参数进行任何操作。通常,自定义元类将主要用于type()
字典,但是它也必须能够与attrs
参数混淆。现在,由于仅在执行类主体语句之后才调用元类,因此运行时无法可靠地在类主体范围中公开bases
,因为这些基数可以在以后由元类修改。
这里还有更多的哲学方面的考虑,特别是wrt / explicit和隐式,并且如shx2所提到的,Python设计人员试图避免魔术变量突然出现。确实有几个实现变量(bases
,在py3中,__module__
)是在类主体名称空间中“自动”定义的,但它们只是名称,主要用作其他调试/检查信息对于开发人员而言),并且绝对不会对类对象的创建或其属性,行为和其他方面产生任何影响。
与Python一样,您必须考虑整个上下文(执行模型,对象模型,不同部分如何协同工作等),才能真正理解设计选择。您是否同意整个设计和哲学是另一个争论(并且不属于这里),但是您可以肯定的是,这些选择 是“有意识的设计决策”。
答案 1 :(得分:2)
我没有回答为什么决定按原样实现,而是回答为什么没有将其实现为“类体中的局部变量”:
仅仅因为python中没有任何东西是在类体中神奇定义的局部变量。 Python不喜欢魔术般地出现的名字。
答案 2 :(得分:0)
这是因为它尚未创建。
请考虑以下内容:
type
假想打印结果如何?
每个python类都是通过int
元类以某种方式创建的。
您在type()
参数中拥有bases
的{{1}}参数,但是您不知道返回值是多少。您可以将其直接用作元类的基础,也可以随LOC返回另一个基础。
刚刚意识到您的to be clear
部分,现在我的回答是无用的哈哈。哦,好了