使用元类与多重继承相结合的类型错误

发布于 2024-08-19 23:51:18 字数 947 浏览 11 评论 0原文

我有两个关于元类和多重继承的问题。第一个是:为什么我会在 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:调用元类基时出错 无法为基础对象创建一致的方法解析顺序(MRO),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:调用元类基类类型时出错.__new__(X): X 不是类型对象 (str)

我正在使用 Python 2.6。

I have two questions converning metaclasses and multiple inheritance. The first is: Why do I get a TypeError for the class Derived but not for 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

The exact error message is:

TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases object, Klass

The second question is: Why does super not work in this case(if I use __init__ instead of __new__, super works again):

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

class Klass(object):
    __metaclass__  = Metaclass

There I get:

TypeError: Error when calling the metaclass bases type.__new__(X):
X is not a type object (str)

I'm using Python 2.6.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心作怪 2024-08-26 23:51:18

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

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

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

>>> 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 是 a y 的子类,然后 x 在 y 之前被访问。在这种情况下不可能同时满足这两个保证。当然,这些保证是有充分理由的:如果没有它们(例如,在旧式类中,仅保证方法解析中的左右顺序,子类约束),x 中的所有重写都将被忽略支持 y 中的定义,但这没有多大意义。想一想:首先从 object 继承,然后再从其他类继承,这意味着什么?该对象(本质上不存在;-)其几个特殊方法的定义必须优先于其他类的定义,从而导致其他类的重写被忽略?

The second question has already been well answered twice, though __new__ is actually a staticmethod, not a classmethod as erroneously claimed in a comment...:

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

The first question (as somebody noted) has nothing to do with metaclasses: you simply can't multiply inherit from any two classes A and B in this order where B is a subclass of A. E.g.:

>>> 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

The MRO guarantees that leftmost bases are visited before rightmost ones - but it also guarantees that among ancestors if x is a subclass of y then x is visited before y. It's impossible to satisfy both of these guarantees in this case. There's a good reason for these guarantees of course: without them (e.g. in old style classes, which only guarantee the left-right order in method resolution, not the subclass constraint) all overrides in x would be ignored in favor of the definitions in y, and that can't make much sense. Think about it: what does it mean to inherit from object first, and from some other class second? That object's (essentially nonexistent;-) definition of its several special methods must take precedence over the other class's, causing the other class's overrides to be ignored?

甩你一脸翔 2024-08-26 23:51:18

第一个问题,看一下python中MRO的说明 - 具体来说,“错误的方法解析顺序”部分。本质上,这是因为 python 不知道是使用对象还是 Klass 的方法。 (这与元类的使用无关。)

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

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

For the first question, have a look at the description of MRO in python - specifically, the "bad Method Resolution order" section. Essentially, it's to do with the fact that python doesn't know whether to use object or Klass's methods. (It's nothing to do with the usage of metaclasses.)

For the second question, it looks like you're misunderstanding how the __new__ function works. It doesn't take a reference to itself as the first argument - it takes a reference to the type of the class being instantiated. So your code should look like this:

class Metaclass(type):
    def __new__(cls, name, bases, dictn):
        return type.__new__(cls, name, bases, dictn)
无所谓啦 2024-08-26 23:51:18

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

For the second question, you need to pass self to __new__ like this:

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

class Klass(object):
    __metaclass__  = Metaclass

I can't recall off the top of my head why this is, but I think it's because type.__new__ isn't a bound method and thus doesn't magically get the self argument.

青丝拂面 2024-08-26 23:51:18

你为什么要这么做?

class Derived(object, Klass):

Klass 已经派生自 object。

class Derived(Klass):

这里是合理的事情。

Why would you do?

class Derived(object, Klass):

Klass already derives from object.

class Derived(Klass):

Is the reasonable thing here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文