首页 > 解决方案 > 具有指定元类的 Python abc 继承

问题描述

如果类指定了元类,那么从 ABC 继承的正确方法是什么?

直截了当的尝试

class KindMeta(type):
    ...

class Kind(ABC, metaclass=KindMeta):
    ...

导致TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

在 KindMeta 中继承 ABCMeta 似乎有点错误,因为这mcs也用于创建非抽象类。

创建从 KindMeta 继承的自定义 ABC 听起来也不好。

有没有更好的处理方法?或者哪个解决方案更pythonic,应该首选?

标签: python-3.xmetaclassabc

解决方案


您必须创建第二个元类,继承自您的原始元类abc.ABCMeta和使用该元类作为您想要的类的元类。

如果你的元类是正确构造的,super()在它实现的所有(特殊)方法中使用调用,它就像这样简单:

import abc 
...

class KindMeta(type):
    ...

class CombinedMeta(KindMeta, abc.ABCMeta):
    pass

class Kind(ABC, metaclass=CombinedMeta):
    ...

如果您的元类没有使用 super(),而是调用硬编码type方法,则必须对其进行更改才能这样做。对于像__prepare__and这样的一些方法__call__,根据你在做什么不调用对应的方法是有意义的 super(),我认为没有必要在ABCMeta. 而且,当然,只有当您不想或不能更改已有的元类,或者如果您希望您的元类用于其他不使用 ABC 的类时,才需要这样做 -

否则,您可以让您自己的元类从ABCMeta自身继承 - 无需创建第三个元类来组合两者:

import abc 
...

class KindMeta(abc.ABCMeta):
    ...

另一方面,如果您使用 Python 的元类 + 类构造机制来创建“不完全类”的对象(例如,zope.interface包确实创建接口),您必须决定 (1) 它是否使完全可以使用它abc.ABC,其次,如果必须运行 ABCMeta 中的对应方法(通常是的,如果您需要该功能)。在这种情况下,您必须适当地自定义您的元类 - 这可能包括强制将类与多重继承组合(即使您可以仅从 ABCMeta 继承)以防止它调用type.__new__(如果这是您的意图):

class KindMeta(type):
    def __new__(mcls, name, bases, ns, **kw):
        cls = ExistingClassRegistry[name]
        return cls

class CombinedMeta(abc.ABCMeta, KindMeta):
    # note the reversed order - ABCMeta will run first
    # and call super().__new__ which runs KindMeta.__new__ and
    # does not forward to type.__new__  
    pass



推荐阅读