Sad*_*aze 10 metaclass abc python-3.x
如果类指定了元类,从 ABC 继承的正确方法是什么?
直接的尝试
class KindMeta(type):
...
class Kind(ABC, metaclass=KindMeta):
...
Run Code Online (Sandbox Code Playgroud)
导致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并且应该是首选?
jsb*_*eno 14
您必须创建第二个元类,从原始元类继承并abc.ABCMeta
使用该元类作为您想要的类的元类。
如果您的元类已正确构造,并使用super()
它实现的所有(特殊)方法中的调用,则它就像以下一样简单:
import abc
...
class KindMeta(type):
...
class CombinedMeta(KindMeta, abc.ABCMeta):
pass
class Kind(ABC, metaclass=CombinedMeta):
...
Run Code Online (Sandbox Code Playgroud)
如果您的元类没有使用 super()
,而是调用硬编码type
方法,则必须更改它才能这样做。__prepare__
对于像和之类的某些方法__call__
,根据您正在执行的操作不调用相应的方法是有意义的
super()
,并且我认为没有必要在 中运行相应的方法ABCMeta
。当然,只有当您不想或无法更改已有的元类,或者您希望您的元类在不使用 ABC 的其他类中使用时,才需要这样做 -
否则,您可以让自己的元类从ABCMeta
自身继承 - 无需创建第三个元类来组合两者:
import abc
...
class KindMeta(abc.ABCMeta):
...
Run Code Online (Sandbox Code Playgroud)
另一方面,如果您使用 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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3229 次 |
最近记录: |