4

我有两个关于元类和多重继承的问题。第一个是:为什么我得到一个 TypeError 的类Derived而不是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: 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)

我正在使用 Python 2.6。

4

4 回答 4

7

第二个问题已经得到了很好的回答两次,虽然__new__实际上是一个静态方法,而不是评论中错误地声称的类方法......:

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

第一个问题(正如有人指出的那样)与元类无关:您根本不能按顺序从任何两个类 A 和 B 继承,其中 B 是 AEg 的子类:

>>> 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 中的定义,这没有多大意义。想一想:从第一个类继承,然后从其他类继承是什么意思?objectobject's (基本上不存在;-) 它的几个特殊方法的定义必须优先于其他类的,导致其他类的覆盖被忽略?

于 2010-02-05T02:53:12.987 回答
4

对于第一个问题,请查看python 中 MRO 的描述- 特别是“错误的方法解决顺序”部分。本质上,这与python不知道是使用对象还是使用Klass的方法有关。(这与元类的使用无关。)

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

class Metaclass(type):
    def __new__(cls, name, bases, dictn):
        return type.__new__(cls, name, bases, dictn)
于 2010-02-04T23:26:02.827 回答
0

对于第二个问题,您需要将 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__不是绑定方法,因此不会神奇地得到 self 参数。

于 2010-02-04T23:28:44.987 回答
0

你为什么要这样做?

class Derived(object, Klass):

Klass 已经派生自对象。

class Derived(Klass):

这是合理的事情。

于 2010-02-05T07:23:01.600 回答