就在我理解元类的时候...
免责声明:我在发帖前四处寻找答案,但我找到的大部分答案都是关于调用 super()
的去另一个@classmethod
在 MRO 中(不涉及元类),或者,令人惊讶的是,他们中的很多人都试图在 metaclass.__new__
中做一些事情。或 metaclass.__call__
这意味着该类尚未完全创建。我很确定(假设是 97%)这不是其中一个问题。
环境:Python 3.7.2
问题:
我有一个元类 FooMeta
定义了一个方法 get_foo(cls)
, 一类 Foo
它是从那个元类构建的(所以是 FooMeta
的一个实例)并且有一个 @classmethod
get_bar(cls)
.然后再上一节课Foo2
继承自 Foo
.在 Foo2
, 我子类 get_foo
通过将其声明为 @classmethod
并调用 super()
.这惨败......
即使用此代码
class FooMeta(type):
def get_foo(cls):
return 5
class Foo(metaclass=FooMeta):
@classmethod
def get_bar(cls):
return 3
print(Foo.get_foo)
# >>> <bound method FooMeta.get_foo of <class '__main__.Foo'>>
print(Foo.get_bar)
# >>> <bound method Foo.get_bar of <class '__main__.Foo'>>
class Foo2(Foo):
@classmethod
def get_foo(cls):
print(cls.__mro__)
# >>> (<class '__main__.Foo2'>, <class '__main__.Foo'>, <class 'object'>)
return super().get_foo()
@classmethod
def get_bar(cls):
return super().get_bar()
print(Foo2().get_bar())
# >>> 3
print(Foo2().get_foo())
# >>> AttributeError: 'super' object has no attribute 'get_foo'
问题:
因此,我的类是元类的一个实例,并且已验证这两个类方法都存在于类 Foo
中。 , 为什么不同时调用 super().get_***()
在里面工作 Foo2
? 我对元类或 super()
有什么不理解的?这让我觉得这些结果不合逻辑?
编辑:进一步测试表明 Foo2
上的方法作为类方法或实例方法不会改变结果。
编辑 2:感谢@chepner 的回答,我认为问题在于 super()
正在返回一个表示 Foo
的 super 对象(这是用 super().__thisclass__
验证的)我期待 super().get_foo()
表现(甚至打电话)get_attr(Foo, 'get_foo')
在幕后。好像不是……我还在想为什么,但是越来越清楚了:)
最佳答案
Foo
可能有一个 get_foo
方法,但是 super
并不是为了检查父类(super class)有哪些属性而设计的。 super
关心哪些属性源自在父类(super class)中。
要理解 super
的设计,请考虑以下多重继承层次结构:
class A:
@classmethod
def f(cls):
return 1
class B(A):
pass
class C(A):
@classmethod
def f(cls):
return 2
class D(B, C):
@classmethod
def f(cls):
return super().f() + 1
A、B、C、D都有一个f
类方法,但是B的f
是继承自A的。D的方法解析顺序,类检查的顺序属性查找,转到 (D, B, C, A, object)
。
super().f() + 1
在 cls
的 MRO 中搜索 f
实现。它应该找到的是 C.f
,但 B 具有继承的 f
实现,并且 B 在 MRO 中位于 C 之前。如果 super
获取 B.f
,这将打破 C
覆盖 f
的尝试,在某些情况下通常称为“菱形继承(钻石问题)”。
super
不查看 B 有哪些属性,而是直接查看 B 的 __dict__
,因此它只考虑 B
实际提供的属性B
的父类(super class)或元类。
现在,回到您的 get_foo
/get_bar
情况。 get_bar
来自 Foo
本身,所以 super().get_bar()
找到 Foo.get_bar
。但是,get_foo
不是由 Foo
提供的,而是由 FooMeta
元类提供的,并且没有 get_foo
的条目在 Foo.__dict__
中。因此,super().get_foo()
什么也没找到。
关于python - 在类的类方法中调用 super() 以获取元类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58703499/