元类冲突、多重继承和实例作为父类

4
我一直在探索Python黑魔法,并想请您帮我理解一些内容。假设有一个类Foo,我尝试从中继承,有以下几种方式:
  1. class A(Foo) — 可行,毫不意外
  2. class B(Foo()) — 在Foo具有适当的__new__方法的情况下可行(我已提供)
  3. class C(Foo(), Foo) — 在与B相同的条件下可行
  4. class D(Foo, Foo()) — 调用出现著名的元类错误:

    Traceback (most recent call last):
       File "test.py", line 59, in
            class D(Foo, Foo()):
    TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

是什么引起了这个冲突呢?当我从(Foo(), Foo)(实例第一,类第二)继承时它可以工作,但是当我从(Foo, Foo())(类第一,实例第二)继承时则不能工作。
1个回答

5
当你“从一个实例继承”时,实际上是使用元类的一种奇怪方式。通常,类对象是type的实例。在上面B类的情况下,它从Foo的一个实例继承。如果定义了以Foo为元类的类,然后从该类继承,则会发生这种情况。
因此,我猜测这里发生的事情是Python按照反向MRO顺序处理基类。
C类可以工作,因为要处理的第一个父类是Foo,其类是type。这意味着D的元类必须是type或其某个子类。然后处理Foo(),其类是Foo,它是type的子类,所以一切正常。
D类失败,因为要处理的第一个父类是Foo(),它设置了一个约束条件,即D必须具有Foo(或子类)的元类。然后处理Foo,其类type不是Foo的子类。
这只是一个猜测,但你可以尝试查看Python关于元类的文档是否要求当您从具有不同元类的两个类中多重继承时,涉及的元类具有子类型关系时,您需要按特定顺序放置它们。

1
@Paul MRO是"方法解析顺序"(method resolution order)的缩写,用于查找方法/属性时类及其父类的检查顺序。我的直觉是,由于第一个父类中的方法会'覆盖'第二个父类中的方法,因此Python会先处理第二个父类,再处理第一个父类。 - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接