将元类与多个继承项结合使用的类型错误

2024-05-14 13:56:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个问题:元类和多重继承。第一个问题是:为什么类Derived而不是Derived2会出现TypeError?

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: Error when calling the metaclass bases Cannot create a consistent method resolution order (MRO) for bases object, Klass

第二个问题是:为什么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: Error when calling the metaclass bases type.__new__(X): X is not a type object (str)

我正在使用Python2.6。


Tags: newgetobjecttypepassthisclassmetaclass
3条回答

对于第二个问题,您需要像这样将self传递给__new__

class Metaclass(type):
    def __new__(self, name, bases, dict_):
        return super(Metaclass, self).__new__(self, name, bases, dict_)

class Klass(object):
    __metaclass__  = Metaclass

我想不起来这是为什么,但我认为这是因为type.__new__不是一个绑定方法,因此不能神奇地得到自论证。

对于第一个问题,请查看the description of MRO in python-特别是“坏方法解析顺序”部分。本质上,这与python不知道是使用object还是Klass的方法有关。(这与使用元类无关。)

对于第二个问题,您似乎误解了__new__函数的工作原理。它不会将对自身的引用作为第一个参数,而是引用要实例化的类的类型。所以你的代码应该是这样的:

class Metaclass(type):
    def __new__(cls, name, bases, dictn):
        return type.__new__(cls, name, bases, dictn)

第二个问题已经被很好地回答了两次,尽管__new__实际上是一个staticmethod,而不是在注释中错误地声明的classmethod…:

>>> class sic(object):
...   def __new__(cls, *x): return object.__new__(cls, *x)
... 
>>> type(sic.__dict__['__new__'])
<type 'staticmethod'>

第一个问题(正如有人所指出的)与元类无关:您不能按照B是A的子类的顺序,将继承从任何两个类A和B进行乘法运算。例如:

>>> 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(本质上不存在;-)定义必须优先于其他类的定义,从而导致其他类的重写被忽略?

相关问题 更多 >

    热门问题