上下文
我开始用python探索元类的概念。很快,我发现自己面临着一个共同的问题。 TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
根据我的理解,当您创建一个继承自两个(或更多)类[a,b]的类[c]时,就会发生这种情况,而这两个类不共享同一个元类[m_a,m_b]
M_A M_B
: :
: :
A B
\ /
\ /
C
这里很好地描述了这个问题,解决方案也很简单。我们需要创建一个新的元类[m_c],它继承自m_a和m_b
我试图通过创建一个动态创建[m_c]的方法,使这个过程自动化。像这样的
我的问题
我的类[c]继承自[b],我想使用[m_a]有它的元类,
m_a是一个自定义元类(singleton)
b的元类是.meta
我的 metaclass_resolver()
成功创建新元类[m_c]
但是它继承自 .ABCMeta
及 type
而不是继承自 .ABCMeta
及 M_A
.
from collections import UserDict
def metaclass_resolver(*classes):
metaclasses = tuple(set(type(cls) for cls in classes))
new_metaclass = metaclasses[0]
new_meta_name = new_metaclass.__name__
#if there's more than one metaclass
#combine them and create a new metaclass (M_C)
if len(metaclasses) > 1:
#get the name of each metaclass
new_meta_name = "_".join(mcls.__name__ for mcls in metaclasses)
#create a new dynamic class
# type('name','bases {inheritance}, attrs)'
new_metaclass = type(new_meta_name, metaclasses, {})
return new_metaclass(new_meta_name, metaclasses, {})
# my custom metaclass (singleton)
class M_A(type):
def __new__(cls, name, bases, attrs):
c = super().__new__(cls, name, bases, attrs)
return c
def __init__(cls, name, bases, attrs):
#When this metaclass is initiated, no instance of the class
#using this metaclass would have been created
cls.__instance = None
super().__init__(name, bases, attrs)
def __call__(cls, *args,**kwargs):
#get the saved instance
instance = cls.__instance
#if the instance does not exists
if instance is None:
#create one
instance = cls.__new__(cls)
instance.__init__(*args,**kwargs)
#save it
cls.__instance = instance
return instance
pass
# abc metaclass
class B(UserDict):
def method_needed_in_C(self):
pass
# my class
class C(B, metaclass = metaclass_resolver(M_A, B)):
def __init__(self):
super().__init__()
print(type(self.__class__))
#<class 'abc.ABCMeta_type'>
pass
if __name__ == "__main__":
c = C()
在里面 metaclass_resolver()
当我使用 type(cls)
它回来了 <class 'type'>
而不是 <class 'M_A'>
因为每个类都是从 type
. 但是,我怎样才能直接指出 <class 'M_A'>
?
如果我使用 cls
我直接得到这个错误: TypeError: descriptor '__init__' requires a 'type' object but received a 'str'
谢谢
1条答案
按热度按时间xn1cxnb41#
你应该只使用
new_metaclass = type(new_meta_name, metaclasses, {})
永远不会new_metaclass(new_meta_name, metaclasses, {})
<-通过这种安排,您正在更改元类的元类-并且您希望元类的元类始终保持不变type
如果您只想组合这两个元类。很可能是由于.meta的意外输入,甚至是您自己的输入
M_A
类,你会得到只有一个祖先元类的副作用。这可能是你意外行为的根源。换言之:要创建元类本身,请调用type,而不是您正在组合的元类中的任何一个,即使它碰巧起作用,对于普通类来说,使这些元类成为“元类”的机制可能并不有用,而且对于作为其他组合元类的元类(包括自身作为祖先)来说,肯定毫无意义。
另一件事是通过使用
tuple(set(...))
为了消除重复的元类,你基本上是随机化它们的顺序:元类是一个敏感的东西,并不是所有的元类都是以一种可以与其他元类组合的方式构建的,而且很少有元类能够以随机顺序组合。您可以改为使用dict理解,这将保留顺序并消除重复项,并且可以在一个步骤中提取元类名称以用于您的奇特命名: