[英]Resolving metaclass conflicts
I need to create a class that uses a different base class depending on some condition.我需要创建一个根据某些条件使用不同基类的类。 With some classes I get the infamous:
在一些课程中,我得到了臭名昭著的:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
One example is sqlite3
, here is a short example you can even use in the interpreter:一个例子是
sqlite3
,这是一个你甚至可以在解释器中使用的简短例子:
>>> import sqlite3
>>> x = type('x', (sqlite3,), {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Instead of using the receipe as mentioned by jdi, you can directly use:您可以直接使用:
class M_C(M_A, M_B):
pass
class C(A, B):
__metaclass__ = M_C
Your example using sqlite3
is invalid because it is a module and not a class.您使用
sqlite3
示例无效,因为它是一个模块而不是一个类。 I have also encountered this issue.我也遇到过这个问题。
Heres your problem: The base class has a metaclass that is not the same type as the subclass.这是您的问题:基类具有与子类不同类型的元类。 That is why you get a
TypeError
.这就是你得到
TypeError
。
I used a variation of this activestate snippet using noconflict.py .我使用 noconflict.py使用了这个 activestate 片段的变体。 The snippet needs to be reworked as it is not python 3.x compatible.
该代码段需要重新编写,因为它与 python 3.x 不兼容。 Regardless, it should give you a general idea.
无论如何,它应该给你一个大致的概念。
Problem snippet问题片段
class M_A(type):
pass
class M_B(type):
pass
class A(object):
__metaclass__=M_A
class B(object):
__metaclass__=M_B
class C(A,B):
pass
#Traceback (most recent call last):
# File "<stdin>", line 1, in ?
#TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass #of the metaclasses of all its bases
Solution snippet解决方案片段
from noconflict import classmaker
class C(A,B):
__metaclass__=classmaker()
print C
#<class 'C'>
The code recipe properly resolves the metaclasses for you.代码配方为您正确解析元类。
This also happens when you try to inherit from a function and not a class.当您尝试从函数而不是类继承时,也会发生这种情况。
Eg.例如。
def function():
pass
class MyClass(function):
pass
To use the pattern described by @michael, but with both Python 2 and 3 compatibility (using the six
library):要使用@michael 描述的模式,但同时兼容 Python 2 和 3(使用
six
库):
from six import with_metaclass
class M_C(M_A, M_B):
pass
class C(with_metaclass(M_C, A, B)):
# implement your class here
As far as I understood from the previous answers the only things we usually have to do manually are:据我从之前的答案中了解到,我们通常需要手动做的唯一事情是:
class M_A(type): pass
class M_B(type): pass
class A(metaclass=M_A): pass
class B(metaclass=M_B): pass
class M_C(M_A, M_B): pass
class C:(A, B, metaclass=M_C): pass
But we can automate the last two lines now by:但是我们现在可以通过以下方式自动化最后两行:
def metaclass_resolver(*classes):
metaclass = tuple(set(type(cls) for cls in classes))
metaclass = metaclass[0] if len(metaclass)==1 \
else type("_".join(mcls.__name__ for mcls in metaclass), metaclass, {}) # class M_C
return metaclass("_".join(cls.__name__ for cls in classes), classes, {}) # class C
class C(metaclass_resolver(A, B)): pass
Since we do not use any version-specific metaclass syntax this metaclass_resolver
works with Python 2 as well as Python 3.由于我们不使用任何特定于版本的元类语法,因此
metaclass_resolver
适用于 Python 2 和 Python 3。
I like doing:我喜欢做:
class mBase1(type):
...
class mBase2(type):
...
class Base1(metaclass=mBase1):
...
class Base2(metaclass=mBase2):
...
class mChild(type(Base1), type(Base2)):
pass
class Child(Base1, Base2, metaclass=mChild):
...
That way if something changes with the metaclass of the bases you don't have to worry about it.这样,如果基类的元类发生变化,您就不必担心。
type()
will take care of it. type()
会处理它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.