Python 中的元类编程 - 理解继承的奥秘和实例创建
2007-03-29 12:10:53 来源:WEB开发网核心提示: 冲突的元类只要您认真地使用元类,至少会遇到一次元类/元型冲突的情况,Python 中的元类编程 - 理解继承的奥秘和实例创建(8),考虑有这样两个类, A 带有元类 M_A ,自己仔细琢磨这些例子,您发现最终会有一天, B 带有元类 M_B ,假设我们从 A 和 B 生成 C
冲突的元类
只要您认真地使用元类,至少会遇到一次元类/元型冲突的情况。考虑有这样两个类, A 带有元类 M_A , B 带有元类 M_B ,假设我们从 A 和 B 生成 C 。问题是 C 的元类是什么呢?是 M_A 还是 M_B 呢?
正确答案是 M_C ,这是一个继承自 M_A 和 M_B 的元类,如下图所示(在本文后面的 参考资料 中,到 Putting metaclasses to work的链接中有这方面的讨论):
图4. 避免元类冲突
然而,Python 不会自动创建 M_C ,相反,它引起一个 TypeError ,警告程序员发生了冲突:
清单14. 元类冲突
>>> 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 # Error message less specific under 2.2
[...]
TypeError: metaclass conflict: the metaclass of a derived class must
be a (non-strict) subclass of the metaclasses of all its bases
为 C 手工创建必需的元类,可以避免元型冲突:
清单15. 手工解决元类冲突
>>> M_AM_B = type("M_AM_B", (M_A,M_B), {})
>>> class C(A,B): __metaclass__ = M_AM_B
...
>>> type(C)
<class 'M_AM_B'>
当您希望越过一个类的祖先向这个类“植入”附加元类的时候,元型冲突问题的解决会变得更加复杂。另外,根据父类的元类的不同,会产生多余的元类——即在不同祖先中的相同元类和在元类之间的超类/子类关系中的相同元类。可以使用模块moconfict来以健壮和自动的方式解决这些问题(见 参考资料)。
结束语
本文讨论了一些具有警示性和比较冷僻的例子,在行为变成直觉习惯之前,使用元类需要某种程度的反复试验。但是,这些问题不是无法解决的――这篇相当短的文章涉及了大多数的陷阱。自己仔细琢磨这些例子,您发现最终会有一天,程序泛化的整个新领域都可以使用元类来达到;为了收益做一些冒险是值得的。
更多精彩
赞助商链接