[Tutor] python varying mulitple inheritance

Steven D'Aprano steve at pearwood.info
Mon Jun 18 03:36:20 CEST 2012


kendy at kendy.org wrote:
> Hello
> 
> I'm new to classes. And I hope the my question isn't too big.
> 
> I have electronic test equipment, but thought that a boat example
> would be easier. Can you help me untangle my class design?
> My problem is basically multiple inheritance, but I want to be
> flexible for how many will inherit.

Your first problem is that you are misusing inheritance when you should be 
using composition instead.

Inheritance is for "is-a" relationships. For example:

Bob is a Person, so Bob should be an instance of Person class.

A Person is a Mammal, so Person should inherit from Mammal class.

A Mammal is an Animal, so Mammal should inherit from Animal class.


Bob has a wallet, he is not a wallet himself. So the Bob instance should have 
an attribute "wallet", storing an instance of Wallet class. This is called 
composition.

In your example, you have a Boat class. Boat is pretty generic, so it might be 
the top-level class. Or it might be a subclass of Vehicle. You might then 
subclass Boat to give SailingBoat, MotorBoat, SpeedBoat, Battleship, etc.

But boats are not kinds of engines, so it is inappropriate for Boat to inherit 
from Engine. A boat (well, at least some boats) has an engine, so you might do 
something like this:


class Boat:
     pass

class SailBoat(Boat):
     def __init__(self, sails):
         self.sails = sails

class RowBoat(Boat):
     def __init__(self, oars):
         self.oars = oars

class PowerBoat(Boat):
     def __init__(self, engine):
         self.engine = engine

class SpeedBoat(PowerBoat):
     """A SpeedBoat is a kind of PowerBoat with an outboard motor."""
     def __init__(self):
         super(SpeedBoat, self).__init__(outboard_motor)

class Yacht(SailBoat):
     """A Yacht is a kind of SailBoat."""
     # Note that the name Yacht is ambiguous, as it is also used for
     # a class of small power boats!
     def __init__(self):
         super(SailBoat, self).__init__(spinnaker)




A boat with both sails and an engine would then use multiple inheritance to 
inherit from both PowerBoat and SailBoat; it would have both an engine and a sail.

Note that when using single-inheritance, you have a choice in how to call the 
parent classes' method:

class K(C):
     def method(self, arg):
         result = C.method(self, arg)  # Call the parent method directly.
         process(result)

or use super:

class K(C):
     def method(self, arg):
         result = super(K, self).method(arg)  # Let Python find the method.
         process(result)


Either way is fine.

BUT once you intend to use multiple inheritance, you MUST use super, or your 
code risks being buggy. NEVER call a superclass method directly using multiple 
inheritance, or even if you might someday want to use multiple inheritance. 
Always use super instead.

(Note: in Python 3, you can simplify the call to super to just super() instead 
of super(K, self). This does not work in Python 2.)

Multiple inheritance is quite tricky to get right, which is why many 
programming languages prohibit it. If you google for "multiple inheritance 
python" you will find many discussions about it, explaining the pros and cons, 
difficulties and alternatives.


One last thing: you will save yourself a lot of pain in the future if you 
stick to a consistent convention for naming things. The usual convention used 
in Python is the classes are named with an initial Capital letter, using 
so-called "CamelCase" if the name has multiple words. Methods, functions, 
attributes and instances are named in lowercase, using underscores to separate 
words: bob_the_builder = Builder(name='Bob').

For more about the suggested (but not compulsory) naming conventions, see this:

http://www.python.org/dev/peps/pep-0008/



-- 
Steven


More information about the Tutor mailing list