0
votes

Why in the code below does metaclass with object base raise metaclass conflict exception?

"metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases"

class M_A(object): pass
class A(object, metaclass = M_A): pass

So does another code:

class M_A(list): pass
class A(object, metaclass = M_A): pass

I understand that the cpython will interpret the above code as:

A = M_A.__new__(M_A, 'A', (object,), {})

What confuses me is that the base class of A is object, and any class is subclass of object. This error is so strange. What's wrong with me?

1
M_A is not a subclass of a metaclass of any base class of A. class M_A(type): pass will probably work. - vaultah
What confuses me is that the base class of A is object, and any class is subclass of object. Is M_A(list) a subclass of a metaclass of any base class of A? I think it is. - ahuigo
@ahui M_A(list) is a subclass of object, yes. But that's not what the error message is about. M_A has to be a subclass of object's metaclass, which is type. - Aran-Fey

1 Answers

3
votes

Let's take a closer look at this error message:

metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

This is a little confusing, so let's take a look at what's what:

  • The "derived class" is A.
  • The "metaclass of a derived class" A is M_A.
  • A's base class is object, therefore "the metaclasses of all its bases" is type - because type is object's metaclass.

This is the problem - object's metaclass is type, but A's metaclass is M_A. Since M_A isn't a subclass of type, python doesn't know which metaclass to use for A and throws an error.


To fix this, change the parent class of M_A to type:

class M_A(type): pass
class A(object, metaclass = M_A): pass

# no errors thrown