I always liked python. It is a rather gentle language with many functional and Object-Oriented characteristics. I was always complaining about python’s Object-Oriented support, and i have a principle as a developer: “If you cannot implement something, do not offer it as a feature”.

Python violates this principle, because it allows developers to use multiple inheritance on a class but does not implement it correctly. Consider the following example:

class ParentOne:
	def __init__(self):
		print "Parent One says: Hello my child!"
		self.i = 1
 
	def methodOne(self):
		print self.i
 
class ParentTwo:
	def __init__(self):
		print "Parent Two says: Hello my child"
 
class Child(ParentOne, ParentTwo):
	def __init__(self):
		print "Child Says: hello"

We have three classes, ParentOne, ParentTwo, and Child. The class Child inherits ParentOne and ParentTwo.

Normally each parent class should be initialised when the child class is initialised through a specified initialisation scheme. Python just do not initialise the parent classes. For example, if we create an instance of the class Child

c = Child()

… we will see in our screen the following output:

bkarak$ python example.py
Child Says: hello

As we can see the __init__ method (aka the constructor) for each parent class is never executed. OOppss.

So, if the ParentOne init method declares a field named “i” (instance field) and the child tries to execute the method, we will end up with the following result:

bkarak$ python example.py
Child Says: hello
Traceback (most recent call last):
  File "example.py", line 20, in 
    c.methodOne()
  File "example.py", line 9, in methodOne
    print self.i
AttributeError: Child instance has no attribute 'i'

Ouch. This fact narrows down the usability of multiple inheritance to simple concatenation of methods with static methods. Really nicely done.

My advice is: “Avoid it, because you are not going to enjoy it”.

I do not really know if something is better implemented in Python 3.0. I will check it and write about it in the distant future.

VN:F [1.9.17_1161]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.17_1161]
Rating: +1 (from 3 votes)
Multiple Inheritance in Python 2.5, 10.0 out of 10 based on 2 ratings

6 Comments

  1. adding ... says:

    yes, it is confusing.

    to get around it, by adding ParentOne.__init__(self) after __init__(self),

    class ParentOne:
    def __init__(self):
    print “Parent One says: Hello my child!”
    self.i = 1

    def methodOne(self):
    print self.i

    class ParentTwo:
    def __init__(self):
    print “Parent Two says: Hello my child”

    class Child(ParentOne, ParentTwo):
    def __init__(self):
    ParentOne.__init__(self)
    print “Child Says: hello”

    c = Child()
    c.methodOne()

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.17_1161]
    Rating: +3 (from 3 votes)
  2. bkarak says:

    My problem with that, was that there is no way to ensure class initialization … unless someone invoked it manually. This needs to be specific, especially if you use complex design with numerous classes.

    VN:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.17_1161]
    Rating: +1 (from 1 vote)
  3. Anthony says:

    It gets worse. The behavior that you pointed out is unintuitive, but at least you could say that Python requires you to manually __init__ superclasses if you define your own __init__. However, the following code gets you into the same situation:

    class ParentOne:
    def __init__(self):
    print “Parent One says: Hello my child!”

    class ParentTwo:
    def __init__(self):
    print “Parent Two says: Hello my child”
    self.i = 1

    def methodOne(self):
    print i

    class Child(ParentOne, ParentTwo):
    def methodTwo(self):
    self.methodOne()

    Note that Child does *not* declare an __init__. Here Python chooses to call __init__ on ParentOne, and completely skips the __init__ of ParentTwo. Totally broken behavior!!

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.17_1161]
    Rating: +1 (from 1 vote)
  4. Alex says:

    I guess this behavior corresponds to one of Python’s principles: “Explicit is better that implicit.”

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.17_1161]
    Rating: +1 (from 1 vote)
  5. Matthijs Kooijman says:

    Actually, the behaviour you describe here is for “Old” classes, which is known to be defective in multiple inheritance situations. Since 2.3, Python offers “new” classes, which are identified by the fact that each top level class inherits from “object”. Also, it requires you to explicitly call the “next” constructor (not that this is not always the parent constructor!) by using super:
    super(Child, self).__init__()

    For more info, see http://www.python.org/download/releases/2.3/mro/

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.17_1161]
    Rating: +1 (from 1 vote)
  6. Matthijs Kooijman says:

    Hmm, it seems new style classes were already present in 2.2, 2.3 only changed the method resolution order slightly.

    Also, the link I gave is probably not really useful, it seems new style classes are a bit underdocumented. Anyway, the following should get you started:
    http://docs.python.org/reference/datamodel.html#new-style-and-classic-classes
    http://www.python.org/doc/newstyle/
    http://fuhm.net/super-harmful/

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.17_1161]
    Rating: +1 (from 1 vote)

Leave a Reply