Python 具有指定元类的 abc 继承
Python abc inheritance with specified metaclass
如果 class 指定了 metaclass,从 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
也用于创建非抽象 classes.
创建继承自 KindMeta 的自定义 ABC 听起来也不太好。
有更好的处理方法吗?或者哪个解决方案更符合 pythonic,应该是首选?
您必须创建第二个元class,从原始元class 和abc.ABCMeta
继承并将该元class 用作元class 在你想要的 classes 上。
如果你的 metaclass 构造正确,在它实现的所有(特殊)方法中使用 super()
调用,它就像:
import abc
...
class KindMeta(type):
...
class CombinedMeta(KindMeta, abc.ABCMeta):
pass
class Kind(ABC, metaclass=CombinedMeta):
...
如果您的元class 没有使用super()
,而是调用硬编码的type
方法,您必须更改它才能这样做。对于某些方法,如 __prepare__
和 __call__
,不调用通讯器是有意义的
super()
方法取决于你在做什么,我认为没有必要 运行 ABCMeta
中对应的方法。
而且,当然,只有在您不想或不能更改您已有的 metaclass,或者如果您希望您的 metaclass 用于其他 [=37] 时,才需要这样做=]es 不使用 ABC -
否则,您可以让自己的元class继承自ABCMeta
本身——无需创建第三个元class来组合两者:
import abc
...
class KindMeta(abc.ABCMeta):
...
另一方面,如果您正在使用 Python 的元class + class 构建机制来创建 "not quite classes" 的对象(例如zope.interface
包确实创建了接口),你必须决定(1)在 abc.ABC
中使用它是否有意义,其次,如果 ABCMeta 中的相应方法必须是 运行(通常是,如果您需要该功能)。在这种情况下,您必须适当地自定义您的元 class - 这可能包括强制将 classes 与多重继承结合(即使您可以从 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
如果 class 指定了 metaclass,从 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
也用于创建非抽象 classes.
创建继承自 KindMeta 的自定义 ABC 听起来也不太好。
有更好的处理方法吗?或者哪个解决方案更符合 pythonic,应该是首选?
您必须创建第二个元class,从原始元class 和abc.ABCMeta
继承并将该元class 用作元class 在你想要的 classes 上。
如果你的 metaclass 构造正确,在它实现的所有(特殊)方法中使用 super()
调用,它就像:
import abc
...
class KindMeta(type):
...
class CombinedMeta(KindMeta, abc.ABCMeta):
pass
class Kind(ABC, metaclass=CombinedMeta):
...
如果您的元class 没有使用super()
,而是调用硬编码的type
方法,您必须更改它才能这样做。对于某些方法,如 __prepare__
和 __call__
,不调用通讯器是有意义的
super()
方法取决于你在做什么,我认为没有必要 运行 ABCMeta
中对应的方法。
而且,当然,只有在您不想或不能更改您已有的 metaclass,或者如果您希望您的 metaclass 用于其他 [=37] 时,才需要这样做=]es 不使用 ABC -
否则,您可以让自己的元class继承自ABCMeta
本身——无需创建第三个元class来组合两者:
import abc
...
class KindMeta(abc.ABCMeta):
...
另一方面,如果您正在使用 Python 的元class + class 构建机制来创建 "not quite classes" 的对象(例如zope.interface
包确实创建了接口),你必须决定(1)在 abc.ABC
中使用它是否有意义,其次,如果 ABCMeta 中的相应方法必须是 运行(通常是,如果您需要该功能)。在这种情况下,您必须适当地自定义您的元 class - 这可能包括强制将 classes 与多重继承结合(即使您可以从 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