【问题标题】:Python abc inheritance with specified metaclass具有指定元类的 Python abc 继承
【发布时间】:2019-12-12 10:00:43
【问题描述】:

如果类指定了元类,那么从 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.x metaclass abc


    【解决方案1】:

    您必须创建第二个元类,继承自您的原始元类和 abc.ABCMeta,并将该元类用作所需类的元类。

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

    import abc 
    ...
    
    class KindMeta(type):
        ...
    
    class CombinedMeta(KindMeta, abc.ABCMeta):
        pass
    
    class Kind(ABC, metaclass=CombinedMeta):
        ...
    

    如果您的元类没有使用super(),而是调用硬编码的type 方法,您必须更改它才能这样做。对于像__prepare____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
    
    
    

    【讨论】:

      猜你喜欢
      • 2020-12-16
      • 2017-12-01
      • 2014-11-15
      • 2021-05-16
      • 2015-05-02
      • 2011-10-06
      • 2020-02-17
      • 2014-05-22
      • 2023-03-23
      相关资源
      最近更新 更多