将元类与多重继承结合使用的 TypeErrors
Posted
技术标签:
【中文标题】将元类与多重继承结合使用的 TypeErrors【英文标题】:TypeErrors using metaclasses in conjunction with multiple inheritance 【发布时间】:2011-01-13 07:42:18 【问题描述】:我有两个关于元类和多重继承的问题。第一个是:为什么我会得到类 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: 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。
【问题讨论】:
【参考方案1】:你为什么要这样做?
class Derived(object, Klass):
类已经派生自对象。
class Derived(Klass):
这里是合理的吗。
【讨论】:
【参考方案2】:第二个问题已经回答了两次,虽然__new__
实际上是一个静态方法,而不是评论中错误声称的类方法...:
>>> 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
的(基本上不存在的;-)它的几个特殊方法的定义必须优先于其他类,导致其他类的覆盖被忽略?
【讨论】:
是有道理的,所以只要我不直接从对象继承(这实际上没有意义,但我想确保没有任何奇怪的事情发生)应该没问题:) 我想知道它是否保存到使用 new 而不使用 super. @nils,是的,__new__
可以在没有 super
的情况下使用——除非在多重继承的复杂情况下。如果您喜欢复杂的多重继承,__new__
会更谨慎。【参考方案3】:
对于第一个问题,请查看the description of MRO in python - 特别是“错误的方法解决顺序”部分。本质上,这与python不知道是使用对象还是使用Klass的方法有关。 (这与元类的使用无关。)
对于第二个问题,您似乎误解了__new__
函数的工作原理。它不引用自身作为第一个参数——它引用被实例化的类的类型。所以你的代码应该是这样的:
class Metaclass(type):
def __new__(cls, name, bases, dictn):
return type.__new__(cls, name, bases, dictn)
【讨论】:
【参考方案4】:对于第二个问题,您需要像这样将 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 参数。
【讨论】:
__new__
是一个类方法,不要在那里使用 self ,这很混乱
是的,在我完成此操作的代码中,我使用了 cls
或类似的东西,但我遵循了原始海报使用的内容。以上是关于将元类与多重继承结合使用的 TypeErrors的主要内容,如果未能解决你的问题,请参考以下文章