473,387 Members | 1,548 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Inheritance Question

I've got an inheritance question and was hoping brighter minds could
guide me. I am in the strange situation where some of the methods in a
subclass are actually more general than methods in a superclass. What
is the preferred way to handle such situations. My original thought was
to do something like this:

class AA(object):
def general_method(): pass

class A(AA):
# redefine general_method() to call a
# restricted version of AA.general_method()

class B(A,AA):
# redefine general_method() to call AA.general_method()

This seems ugly to me, and I am wondering if there is a better method.
So any suggestions would be appreciated.
Thanks!


-----------

For a more "concrete" example:

Suppose all the animals in the world have only 1 or 2 legs.

class Legs(object)
def run(): pass
def walk(number_of_legs):
# lots of commands
# that do not depend on the
# number of legs but definitely
# have to do with walking

if number_of_legs == '1':
# blah blah

if number_of_legs == '2':
# blah blah

# more commands

class HasAtLeastOneLeg(Legs):
def walk():
# Legs.walk(number_of_legs=1)

class HasTwoLegs(HasAtLeastOneLeg,Legs):
def walk()
# Legs.walk(number_of_legs=2)

# isinstance(HasTwoLegs, HasAtLeastOneLeg) --True
Nov 10 '06 #1
6 1490
At Friday 10/11/2006 21:13, Jackson wrote:
>I've got an inheritance question and was hoping brighter minds could
guide me. I am in the strange situation where some of the methods in a
subclass are actually more general than methods in a superclass. What
is the preferred way to handle such situations. My original thought was
to do something like this:

class AA(object):
def general_method(): pass

class A(AA):
# redefine general_method() to call a
# restricted version of AA.general_method()

class B(A,AA):
# redefine general_method() to call AA.general_method()

This seems ugly to me, and I am wondering if there is a better method.
So any suggestions would be appreciated.
(Note that even using your design, B doesn't have to inherit from
both A and AA, just inheriting from A is enough to be able to call
AA.general_method)

It's hard to tell in this abstract terms, but maybe you should
consider whether really B "is an" A, and A "is an" AA.
Other kind of relationships are possible, like delegation ("behaves
like") or the strategy pattern ("now behaves like...", at runtime).
>For a more "concrete" example:
Ahhhh! I didn't notice this when I read your post.
>Suppose all the animals in the world have only 1 or 2 legs.
I would not consider walk a method of Legs, but of Animal. An Animal
"has" Legs; it may have OneLeg or TwoLegs. An Animal walks "using" its legs.

class Animal:
def __init__(self, number_of_legs):
# an animal has legs
self.legs = CreateLegs(self, number_of_legs)

def walk(self):
# an animal uses its legs to walk
self.legs.walk()

class Legs:
def walk():
raise NotImplementedError # an abstract Legs doesn't have how to walk

class OneLeg(Legs): # a monopod? like in Plinius?
"http://en.wikipedia.org/wiki/Monopod_(creature)"
def walk():
# implement walking with one leg
print "Look ma, just one leg!"

class TwoLegs(Legs):
def walk():
# implement walking with two legs
print "Left, rigth, left, right..."

def CreateLegs(animal, number_of_legs):
# legs might depend on animal too
if number_of_legs==1: return OneLeg()
elif number_of_legs==2: return TwoLegs()
raise ValueError, "Invalid number of legs: %d" % number_of_legs

If walking in general, have some common structure, you can put the
"sketch" on Legs and let the derived classes "fill the gaps". This is
known as "Template Method Pattern" - look for it.
--
Gabriel Genellina
Softlab SRL

__________________________________________________
Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ˇgratis!
ˇAbrí tu cuenta ya! - http://correo.yahoo.com.ar
Nov 11 '06 #2
Gabriel Genellina wrote:
If walking in general, have some common structure, you can put the
"sketch" on Legs and let the derived classes "fill the gaps". This is
known as "Template Method Pattern" - look for it.
Or if you'd rather see a concrete example, here's how your toy example
would look refactored using the template pattern:

class Creature(object)
def run(): pass
def walk():
# lots of commands
# that do not depend on the
# number of legs but definitely
# have to do with walking

self._specialized_walk(*args, **kwds)

# more commands

def _specialized_walk(self, *args):
raise NotImplementedError
class UnipedalCreature(Creature):
def _specialized_walk(self, *args, **kwds):
# blahblah
class BipedalCreature(Creature):
def _specialized_walk(self, *args, **kwds):
# blahblah
HTH,
George

Nov 11 '06 #3

Jackson wrote:
I've got an inheritance question and was hoping brighter minds could
guide me. I am in the strange situation where some of the methods in a
subclass are actually more general than methods in a superclass. What
is the preferred way to handle such situations. My original thought was
to do something like this:

class AA(object):
def general_method(): pass

class A(AA):
# redefine general_method() to call a
# restricted version of AA.general_method()

class B(A,AA):
# redefine general_method() to call AA.general_method()

This seems ugly to me, and I am wondering if there is a better method.
So any suggestions would be appreciated.
I don't have an answer, but I have a similar question, so I hope you
don't mind if I add it to this thread. Hopefully there will be some
commonality in the responses.

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?

Thanks

Frank Millman

Nov 11 '06 #4
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,EatNormallyCapabili ty): # walks
normally, eats normally
pass

class
AWdEn(A,WalkDifferentCapability,EatNormallyCapabil ity): # 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
Nov 11 '06 #5

Gabriel Genellina wrote:
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?
[snip]
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.
[snip details]
>
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).
[snip details]

Many thanks for this, Gabriel.

I have seen explanations like this before, but my eyes usually glaze
over before I have finished, and I end up more confused than when I
started.

With a combination of my subconscious slowly getting an understanding
of this, and your clear explanation, I think I have finally got it.

Obviously my real world situation is quite a bit more complex than this
simple example, but with the help you have given me I can now
experiment with different ideas and decide on the best strategy.

Thanks again

Frank

Nov 11 '06 #6
Jackson wrote:
For a more "concrete" example:

Suppose all the animals in the world have only 1 or 2 legs.

class Legs(object)
def run(): pass
def walk(number_of_legs):
# lots of commands
# that do not depend on the
# number of legs but definitely
# have to do with walking

if number_of_legs == '1':
# blah blah

if number_of_legs == '2':
# blah blah

# more commands

class HasAtLeastOneLeg(Legs):
def walk():
# Legs.walk(number_of_legs=1)

class HasTwoLegs(HasAtLeastOneLeg,Legs):
def walk()
# Legs.walk(number_of_legs=2)
Well, I would have done this differently. If the only difference in
behavior between one- and two-legged creatures is their gait, I
probably wouldn't have bothered breaking Legs into subclasses. I'd
just pass the number of legs into __init__:

class Legs(object):
def __init__(self,number_of_legs):
self.number_of_legs = number_of_legs
def walk(self):
# non-legs-dependent stuff
if self.number_of_legs == 1:
# one-legged gait
elif self.number_of_legs == 2:
# two-legged gait
else:
raise ValueError("invalid number of legs")
# more non-legs-dependent stuff

Then, when defining some sort of monster class, I'd do something like
this:

class Human(object):
def __init__(self):
self.legs = Legs(2)
# etc.

class Dufflepud(object):
def __init__(self):
self.legs = Legs(1)
# etc.

If there's more to it than just gait (say for example, one-legged
creatures attack differently, jump higher, and can't turn invisible
because they don't have enough limbs to cast Level 4 Invisibility),
then I would factor out differences in behavior into subclasses.

class Legs(object):
def walk(self):
# non-leg-related stuff
self.set_gait()
# more non-leg-related stuff

class OneLeg(Legs):
def set_gait(self):
# set the one-legged gait

class TwoLegs(Legs):
def set_gait(self):
# set the two-legged gait

class Human(object):
def __init__(self):
self.legs = TwoLegs()

class Dufflepud(object):
def __init__(self):
self.legs = OneLeg()
ISTM you have been missing out on the true power of inheritance.
Behavior exclusive to creatures with two legs should be implmented in
the TwoLegs class, but in your example you define a HasTwoLegs class
yet still implement this behavior in the base class Legs. That's just
poor use of inheritance. My examples implement behavior exclusive to
two-legged creatures inside the TwoLegs class, where it belongs.

In fact, BEHAVIOR is the key to arranging class hierarchies. (The
classical advice, the inheritance represents the "is a" relationship,
can be very misleading and I don't recommend using it. The focus
should be on behavior.) Anyways, in your universe, there are three
kinds of behaviors:

A. behaviors exclusive to one-footed creatures
B. behaviors exclusive to two-footed creatures
C. behaviors common to both

Once you consider behaviors in this way, how to arrange the class
hierarchy becomes obvious. Each kind of behavior shoud be implemented
in its own class: common behaviors go into base classes, exclusive
behaviors into subclasses. The hierarchy should look like this:

class Legs -- this should implement all common behavior
class OneLeg(Legs) -- should implment all behavior exclusive to
one-legged creatures
class TwoLegs(Legs) -- should implment all behavior exclusive to
two-legged creatures

Note that there's no need for an AtLeastOneLeg class. There are only
one- and two-legged creatures in this univserse, so behaviors exclusive
to creatures with at least one leg apply are in fact common to all
creatures. But suppose we add zero-footed creatures to the universe.
Now we identify five kinds of behaviors:

A. behaviors common to all creatures
B. behaviors exclusive to zero-footed creatures
C. behaviors common to one- and two-footed creatures
D. behaviors exclusive to one-footed creatures
E. behaviors exclusive to two-footed creatures

Now we need an AtLeastOneLeg class in our hierarchy:

class Legs
class ZeroLegs(Legs)
class AtLeastOneLeg(Legs)
class OneLeg(AtLeastOneLeg)
class TwoLegs(AtLeastOneLeg)

But, notice that we still have a OneLeg class, because there's still
behavior exclusive to one-legged creatures. It belongs in OneLeg, not
in AtLeastOneLeg.

Hope this long-winded advice helps.
Carl Banks

Nov 11 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: KK | last post by:
Windows Forms Inheritance, Incomplete? I was playing around with Windows Forms and found out this Forms Inheritance feature. The moment I saw that, I felt this can be used effectively if the...
2
by: KK | last post by:
** Posting it here cause after couple of days no body responded.** I was playing around with Windows Forms and found out this Forms Inheritance feature. The moment I saw that, I felt this can...
4
by: Dave Theese | last post by:
Hello all, The example below demonstrates proper conformance to the C++ standard. However, I'm having a hard time getting my brain around which language rules make this proper... The error...
8
by: __PPS__ | last post by:
Hello everybody, today I had another quiz question "if class X is privately derived from base class Y what is the scope of the public, protected, private members of Y will be in class X" By...
22
by: Matthew Louden | last post by:
I want to know why C# doesnt support multiple inheritance? But why we can inherit multiple interfaces instead? I know this is the rule, but I dont understand why. Can anyone give me some concrete...
45
by: Ben Blank | last post by:
I'm writing a family of classes which all inherit most of their methods and code (including constructors) from a single base class. When attempting to instance one of the derived classes using...
6
by: VR | last post by:
Hi, I read about Master Pages in ASP.Net 2.0 and after implementing some WinForms Visual Inheritance I tryed it with WebForms (let's say .aspx pages, my MasterPage does not have a form tag itself...
5
by: Noah Roberts | last post by:
Is there anything that says that if you virtually inherit from one class you have to virtually inherit from anything you inherit from?
3
by: RSH | last post by:
I have a simple question regarding inheritance in a web form. I have a DropDownList in an aspx form. It is called DropDownList1 I have a class that will be overriding the render event so I...
8
by: RSH | last post by:
Hi, I am working on some general OOP constructs and I was wondering if I could get some guidance. I have an instance where I have a Base Abstract Class, and 4 Derived classes. I now need to...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.