使用元类和多重继承时的类型错误
我有两个关于 metaclasses(元类)和多重继承的问题。第一个问题是:为什么我在使用 Derived
类时会出现 TypeError 错误,而在使用 Derived2
时却没有?
class Metaclass(type): pass
class Klass(object):
__metaclass__ = Metaclass
#class Derived(object, Klass): pass # if I uncomment this, I get a TypeError
class OtherClass(object): pass
class Derived2(OtherClass, Klass): pass # I do not get a TypeError for this
具体的错误信息是:
TypeError: 调用元类基础时出错
无法为基础对象、Klass 创建一致的方法解析顺序(MRO)
第二个问题是:为什么在这种情况下 super
不起作用(如果我用 __init__
替代 __new__
,super
又可以正常工作):
class Metaclass(type):
def __new__(self, name, bases, dict_):
return super(Metaclass, self).__new__(name, bases, dict_)
class Klass(object):
__metaclass__ = Metaclass
在这里我得到的错误是:
TypeError: 调用元类基础时出错 type.__new__(X):
X 不是一个类型对象(str)
我使用的是 Python 2.6。
4 个回答
你为什么要这么做呢?
class Derived(object, Klass):
这个类已经是从对象(object)派生出来的了。
class Derived(Klass):
这样做是合理的。
对于第一个问题,可以看看Python中MRO的描述,特别是“坏的方法解析顺序”这一部分。简单来说,这个问题是因为Python不确定是使用对象的方法还是Klass的方法。(这和元类的使用没有关系。)
对于第二个问题,似乎你对__new__
函数的工作原理有些误解。它的第一个参数并不是指向它自己的引用,而是指向正在实例化的类的类型。所以你的代码应该像这样:
class Metaclass(type):
def __new__(cls, name, bases, dictn):
return type.__new__(cls, name, bases, dictn)
第二个问题已经有两次很好的回答了,不过有个评论错误地说 __new__
是类方法,其实它是静态方法……:
>>> class sic(object):
... def __new__(cls, *x): return object.__new__(cls, *x)
...
>>> type(sic.__dict__['__new__'])
<type 'staticmethod'>
第一个问题(正如有人提到的)和元类没有关系:你不能按照这个顺序从两个类 A 和 B 进行多重继承,其中 B 是 A 的子类。例如:
>>> class cis(sic): pass
...
>>> class oops(sic, cis): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases sic, cis
方法解析顺序(MRO)保证了最左边的基类会在最右边的基类之前被访问,但它也保证了如果 x 是 y 的子类,那么 x 会在 y 之前被访问。在这种情况下,无法同时满足这两个保证。当然,这些保证是有原因的:如果没有它们(比如在旧式类中,只保证了方法解析的左右顺序,而不是子类约束),那么 x 中的所有重写都会被 y 中的定义所忽略,这样就没有什么意义了。想想看:首先从 object
继承,然后再从其他类继承,这到底意味着什么呢?这是不是意味着 object
的(几乎不存在的;-) 特殊方法的定义必须优先于其他类的定义,导致其他类的重写被忽略?