[Tutor] super() with Multiple Inheritance

Steven D'Aprano steve at pearwood.info
Fri Apr 15 02:48:13 CEST 2011


James,

Your subject line is misleading: you ask about *multiple* inheritance, 
but the code you use is *single* inheritance:

object
-> Element
    -> Vertex
       -> Person
          -> User


Multiple inheritance occurs when you have a class that inherits from two 
or more parent classes:


class Spam(Ham, ManufacturedMeatProduct):
     [...]


This is often problematic, so much so that many object oriented 
languages prohibit it, or limit it to a subset of MI where the second 
parent shares no methods with the first ("mixins").

Python allows almost unrestricted MI, but I strongly recommend that you 
avoid it unless absolutely necessary.

Also, it's quite unusual in Python to build long inheritance chains like 
this. We're a pragmatic people, we Python coders, and if a class only 
exists to satisfy some sense of theoretical object-hierarchy purity, 
more often than not we prefer the Zen of Python:

 >>> import this
[...]
Practicality beats purity.


I'd consider reducing the hierarchy to:

object
-> Element
    -> User


unless you have real need for the other classes.



James Thornton wrote:
> Why does user.params() not return all the params up the inheritance
> chain? -- It's not including the params defined in Person() -- notice
> Vertex() does not have a params() method.

You do something fairly unusual here:

> class Person(Vertex):
>     def __init__(self,name=None,uri=None,email=None):
>         self.s = super(Person,self)
>         self.s.__init__()

I've never seen anyone *store* a super object before! Normally people 
generate it as needed:

     super(Person, self).__init__()


This leads to your mistake:

> class User(Person):
>     def __init__(self, [...])
>         self.s = super(User,self)
>         self.s.__init__(name,uri,email)

So you store the User's super object as attribute "s", and then call the 
superclasses' __init__ method... but Person's __init__ in turn *also* 
stores its super object as "s", thus *over-writing* the "s" you just 
saved. Then, when you call params:

>     def params(self):
>         params = dict(...)
>         print self.s.params()
>         params.update(self.s.params())
>         return params

self.s is the super object for Person, not User, and so it skips Person 
and goes directly to Vertex, Element and object.

TL;DR: don't save super objects for later use, they're not that 
expensive to make. Just regenerate them as needed.



-- 
Steven



More information about the Tutor mailing list