[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