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

Posted

技术标签:

【中文标题】元类冲突、多重继承、实例为父【英文标题】:Metaclass conflict, multiple inheritance, and instance as parent 【发布时间】:2011-11-20 22:49:41 【问题描述】:

我一直在玩 Python 的黑暗艺术,有一些我想帮助理解的东西。给定一个类Foo,下面是我尝试从它继承的一些方法:

    class A(Foo) — 工作,不出所料 class B(Foo()) — 提供的作品 Foo 有一个合适的 __new__ 方法(我提供了) class C(Foo(), Foo) — 在与 B 相同的条件下工作 class D(Foo, Foo()) — 给出著名的元类错误:

    回溯(最近一次通话最后一次): 文件“test.py”,第 59 行,在 D类(Foo,Foo()): TypeError:元类冲突:派生类的元类必须是(非严格) 其所有基础的元类的子类

究竟是什么导致了这种冲突?当我从(Foo(), Foo)(实例第一,类第二)继承时,它可以工作,但是当我从(Foo, Foo())(类第一,实例第二)继承时,它不会。

【问题讨论】:

【参考方案1】:

当你“从一个实例继承”时,你真正在做的是一种使用元类的奇怪方式。通常,类对象是type 的实例。对于上面的 B 类,它继承自 Foo 的实例。如果您定义一个以 Foo 作为元类的类,然后从该类继承,这正是会发生的情况。

所以我对这里发生的事情的猜测是 Python 正在以相反的 MRO 顺序处理基类。

C 类有效,因为要处理的第一个父类是Foo,其类是type。这意味着 D 的元类必须是type,或其某个子类。然后处理Foo(),其类为Foo,是type的子类,所以一切正常。

类 D 失败,因为要处理的第一个父类是 Foo(),它设置了一个约束,即 D 具有 Foo(或子类)的元类。然后Foo 出现,其类type 不是 Foo 的子类。

这是一个完整的猜测,但是您可以尝试查看有关元类的 Python 文档是否要求当您从具有不同元类的两个类(其中所涉及的元类具有子类型关系)相乘继承时,您将它们按特定顺序放置.

【讨论】:

@Paul MRO 是“方法解析顺序”,即在查找方法/属性时检查类及其父类的顺序。我的直觉是,由于第一个父级中的方法“覆盖”了第二个父级中的方法,Python 将处理第二个,然后处理第一个。

以上是关于元类冲突、多重继承、实例为父的主要内容,如果未能解决你的问题,请参考以下文章

涉及 Enum 的多重继承元类冲突

将元类与多重继承结合使用的 TypeErrors

来自元类工厂的多重继承

三重继承导致元类冲突......有时

三重继承导致元类冲突......有时

Django:从带有元的抽象类的多重继承