Classes are just like instances; they have a type. For instances that type is the class, but for classes, the type is called a metaclass. Inheriting from a class normally would call the metatype of the base class to produce a new class object (using type(base)
; for multiple bases restrictions apply). The standard metatype is the type
object, but you can create your own metaclasses.
By inheriting from an instance, Python tries to create a new class by calling type(obj)(classname, bases, body_namespace)
. Since type(obj)
is X
and X.__init__()
doesn't support those arguments, the call fails. However, there is nothing stopping you from making that part work!
>>> class X:
... def __init__(self, classname, parents, namespace):
... print('Creating {}{}'.format(classname, parents))
...
>>> class Child(X('X', (), {})): pass
...
Creating X()
Creating Child(<__main__.X object at 0x10372b4a8>,)
>>> Child
<__main__.X object at 0x10372b470>
>>> Child()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'X' object is not callable
Of course, type
provides a lot more functionality that a class won't offer out of the box; there are a series of descriptors to provide attributes on a class that other parts of Python expect to exist. Your class would have to cover all of those instead; in the above sample output, you'll note that repr(Child)
produces <__main__.X object at 0x...>
rather than the expected <class '__main__.Child'>
, and there is no __call__
method to produce instances for the class. So using an instance as a base class for another can work, you just have to put in the extra work to define all that expected functionality.
In the end, using an instance as a base class may be possible, but has no practical uses, not when any of the use-cases are already covered by metaclasses instead.