In the python tutorial it's said that "Python supports a limited form of multiple inheritance".
What are the limitations?
Yes, Python supports multiple inheritance. Like C++, a class can be derived from more than one base classes in Python. This is called Multiple Inheritance.
A class can be derived from more than one base class in Python, similar to C++. This is called multiple inheritance. In multiple inheritance, the features of all the base classes are inherited into the derived class.
I'm not sure to what limitations the author of the python tutorial was referring, but I would guess it has in part to do with the way that method / attribute lookup is implemented in python (the "method resolution order" or MRO). Python uses the C3 superclass linearization mechanism; this is to deal with what is termed to be "The Diamond Problem".
Once you've introduced multiple inheritance into your class hierarchy, any given class doesn't have a single potential class that it inherits from, it only has "the next class in the MRO", even for classes that expect that they inherit from some class in particular.
For example, if class A(object)
, class B(A)
, class C(A)
, and class D(B, C)
, then the MRO for class D
is D->B->C->A
. Class B might have been written, probably was, thinking that it descends from A, and when it calls super()
on itself, it will get a method on A. But this is no longer true; when B calls super()
, it will get a method on C instead, if it exists.
If you change method signatures in overridden methods this can be a problem. Class B, expecting the signature of a method from class A when it calls super, instead gets a method from C, which might not have that signature (and might or might not not implement the desired behavior, from class B's point of view).
class A(object): def __init__(self, foo): print "A!" class B(A): def __init__(self, foo, bar): print "B!" super(B, self).__init__(foo) class C(A): def __init__(self, foo, baaz): print "C!" super(C, self).__init__(foo) class D(B, C): def __init__(self, foo, bar): print "D!" super(D, self).__init__(foo, bar) print D.mro() D("foo", "bar")
In this code sample, classes B and C have reasonably extended A, and changed their __init__
signatures, but call their expected superclass signature correctly. But when you make D like that, the effective "superclass" of B becomes C instead of A. When it calls super, things blow up:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>] D! B! Traceback (most recent call last): File "/tmp/multi_inherit.py", line 22, in <module> D("foo", "bar") File "/tmp/multi_inherit.py", line 19, in __init__ super(D, self).__init__(foo, bar) File "/tmp/multi_inherit.py", line 9, in __init__ super(B, self).__init__(foo) TypeError: __init__() takes exactly 3 arguments (2 given)
This same sort of thing could happen for other methods as well (if they call super()
), and the "diamond" doesn't have to only appear at the root of the class hierarchy.
Apart from @Matt Anderson's answer I think that the limitations is in fact for the old style classes (which the tutorial for Python 2.6 still addresses).
In the Python 3 tutorial the text is now: Python supports a form of multiple inheritance as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With