multiple inheritance

Duncan Booth duncan.booth at invalid.invalid
Thu Jun 9 10:48:21 CEST 2005

newseater wrote:

> if I only use the super() construct it seems not to call B
> class A(object):
>      def foo(self):
>           print "a"
> class B(object):
>      def foo(self):
>           print "b"
> class C(A,B):
>      def foo(self):
>           print "c"
>           super(C,self).foo()
> c = C()
> produces
> c
> a

That is because a single call to super only calls a single method from one 
base class. Each call to super works out which is the next method that 
should be called and calls it, but it is then up to that method to ensure 
the call gets passed on along the chain.

The problem with super is that you need to be sure to terminate that 
calling chain somehow. You can do what Andreas did, and use getattr to 
check for the existence of the base class method, but that gets messy. I 
find the easiest way is to define the interface in an abstract base class 
which deliberately doesn't pass the call upwards:

class IFoo(object):
    def foo(self):

class A(IFoo):
    def foo(self):
        print "a"

class B(IFoo):
    def foo(self):
        print "b"

class C(A,B):
    def foo(self):
        print "c"

>>> A().foo()
>>> B().foo()
>>> C().foo()

You can also ask a class the order in which its base classes are examine 
for methods:

>>> C.mro()
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 
'__main__.IFoo'>, <type 'object'>]

This is how super works, 'super(A, self)' when self is a C returns an 
object which will look at self.__class__.mro(), which is the list above, 
finds the class A, and then searches the remaining classes for matching 
attributes (B, IFoo, then object). The same super call on an instance of A 
gets a shorter list which doesn't include B as a possible target:

>>> A.mro()
[<class '__main__.A'>, <class '__main__.IFoo'>, <type 'object'>]

More information about the Python-list mailing list