TypeErrors using metaclasses in conjunction with multiple inheritance

三世轮回 提交于 2019-12-04 10:01:01

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?

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)

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.

Why would you do?

class Derived(object, Klass):

Klass already derives from object.

class Derived(Klass):

Is the reasonable thing here.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!