I’ve been messing around with the dark arts of Python and there’s something I’d like help understanding. Given a class Foo, here’s some ways I attempted to inherit from it:
class A(Foo)— Works, unsurprizinglyclass B(Foo())— works providedFoohas an appropriate__new__method (which I provided)class C(Foo(), Foo)— works, under the same conditions asBclass D(Foo, Foo())— gives the famous metaclass error:
Traceback (most recent call last):
File “test.py”, line 59, in
class D(Foo, Foo()):
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
What exactly is it that causes this conflict? When I inherit from (Foo(), Foo) (instance first, class second) it works, but when I inherit from (Foo, Foo()) (class first, instance second), it doesn’t.
When you “inherent from an instance”, what you’re really doing is a strange way of using a metaclass. Normally, class objects are instances of
type. In the case of class B above, it inherits from an instance ofFoo. This is exactly what would happen if you defined a class withFooas its metaclass, and then inherited from that.So my speculation as to what’s happening here is that Python is processing the base classes in reverse MRO order.
Class C works because the first parent class to be processed is
Foo, whose class istype. This means that the metaclass of D must betype, or some subclass thereof. ThenFoo()is processed, whose class isFoo, which is a subclass oftype, so everything’s fine.Class D fails because the first parent class to be processed is
Foo(), which sets a constraint that D have a metaclass ofFoo(or subclass). ThenFoocomes along, whose classtypeis not a subclass ofFoo.That is a complete guess, but you could try and see if the Python documentation on metaclasses requires when you multiply inherit from two classes with different metaclasses, where the metaclasses involved have a subtype relationship, that you put them in a particular order.