Re: Inheritance Question



At Saturday 11/11/2006 03:31, Frank Millman wrote:

Continuing your analogy of animals, assume a class A with a 'walk'
method and an 'eat' method.

Most animals walk the same way, but a few don't, so I create a subclass
AW and override the walk method.

Most animals eat the same way, but a few don't, so I create a subclass
AE and override the eat method.

How do I create an instance of an animal that both walks and eats
differently?

This is how I do it at present.

class A(object): # walks normally, eats normally
def walk(self):
normal walk
def eat(self):
normal eat

class AW(A): # walks differently, eats normally
def walk(self):
different walk

class E(object): # abstract class
def eat(self):
different eat

class AE(E,A): # walks normally, eats differently
pass

class AWE(E,AW): # walks differently, eats differently
pass

So I use multiple inheritance instead of subclassing to override the
eat method. It works, but it feels ugly. Is there a cleaner solution?

Answer 1) Move *both* ways of walk, and *both* ways of eating, to another base class. Best when this is pure behavior - no new attributes are involved.

class A(object): # does not know how to walk, neither how to eat
def walk(self):
raise NotImplemented
def eat(self):
raise NotImplemented

class WalkNormallyCapability(object): # knows how to walk normally
def walk(self):
normal walk

class WalkDifferentCapability(object): # knows how to walk different
def walk(self):
different walk

class EatNormallyCapability(object): # knows how to eat normally
def eat(self):
normal eat

class EatDifferentCapability(object): # knows how to eat different
def eat(self):
different eat

class AWnEn(A,WalkNormallyCapability,EatNormallyCapability): # walks normally, eats normally
pass

class AWdEn(A,WalkDifferentCapability,EatNormallyCapability): # walks different, eats normally
pass
....etc.

The xxxCapability classes are usually referred as "mixin class" - they add a new capability to an existing class, without adding new attributes (they could, but initialization gets more complicated, you must rewrite __init__ and so...). They may inherit from a common base class, too, but that's not required in Python.


Answer 2) Use an instance of another class to define how to walk and how to eat. Advantage: it can later be modified at runtime (strategy pattern).

class A(object):
def __init__(self, walker, eater):
self.walker=walker
self.eater=eater
def walk(self):
self.walker.walk()
def eat(self):
self.eater.eat()

class NormalWalker(object): # knows how to walk normally
def walk(self):
normal walk

class DifferentWalker(object): # knows how to walk different
def walk(self):
different walk

class NormalEater(object): # knows how to eat normally
def eat(self):
normal eat

class DifferentEater(object): # knows how to eat different
def eat(self):
different eat

a=A(NormalWalker(), DifferentEater())
or define a factory function when you decide which walker an which eater to use based on its arguments. As above, they may inherit from a common base class (Walker, Eater, by example).



--
Gabriel Genellina
Softlab SRL

__________________________________________________
Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ¡gratis! ¡Abrí tu cuenta ya! - http://correo.yahoo.com.ar
.



Relevant Pages

  • Re: Inheritance Question
    ... Most animals walk the same way, but a few don't, so I create a subclass ... AW and override the walk method. ... Most animals eat the same way, but a few don't, so I create a subclass ...
    (comp.lang.python)
  • Re: Inheritance Question
    ... def general_method: pass ... Most animals walk the same way, but a few don't, so I create a subclass ... Most animals eat the same way, but a few don't, so I create a subclass ...
    (comp.lang.python)
  • Re: How to make Python poll a PYTHON METHOD
    ... The example above creates a thread to call a function "eat" every time ... When the next interval is up this process repeat itself. ... -Nick Vatamaniuc ... def stop_repeating: ...
    (comp.lang.python)
  • Re: Alternate initializers or alternate class?
    ... class OrderHash ... def self.auto ... please have your cake and eat it too. ...
    (comp.lang.ruby)
  • Re: Alternate initializers or alternate class?
    ... > class OrderHash ... > def self.auto ... please have your cake and eat it too. ...
    (comp.lang.ruby)