[Tutor] design questions: pythonic approach to ostriches

Brian van den Broek bvande at po-box.mcgill.ca
Sat Apr 23 18:19:20 CEST 2005


Hi all,

I am wondering about the Pythonic way to handle the problem of 
ostriches, emus, and penguins. (I cannot recall from where I got the 
example.)

Here's what I mean:

class Bird(object):
     def fly(self):
         # flying logic here
     def lay(self):
         # egg-laying logic here
     # more bird methods

class Ostrich(Bird):
     # ostriches can't fly, so what to do?

I've explored a number of solutions; here they are with what I see as 
to cons and problems:


The simplest thing is to emulate the ostrich and pretend the problem 
doesn't exist. But, putting one's head in the sand looks likely to 
cause troubles in that this route break encapsulation, requiring 
callers to know enough not to call the fly method of an ostrich. So, 
that's no good.


class Ostrich(Bird):
     def fly(self):
         pass

seems only marginally better, in that it gives the external appearance 
of flight, whereas what is needed is a "Hey, I don't fly" signal.


The next thought was to over-ride Ostrich.fly as
     def fly(self):
          raise NotImplementedError

That seems better, but also a bit confusing; the way I understand it, 
NotImplementedError is, in the first instance, for abstract classes or 
for marking work in progress. But Ostrich.fly doesn't fit either case.


That makes me think to define a custom exception, say

class OstrichError(NotImplementedError):
     '''A custom exception for cases of the "Ostrich problem".

     Intended to be raised by methods in a subclass over-riding methods
     of the parent which don't make sense for the subclass to actually
     implement.'''
     def __init__(self):
         NotImplementedError.__init__(self)

But, since the problem isn't one that my penetrating genius 
discovered, I am inclined to think that were this the ideal solution, 
there'd be a (better named) exception class builtin to Python already.


A complicated class hierarchy like

class Bird(object):
     # bird logic

class FlyingBird(Bird):
     def fly(self):
         # flying logic here

class FlightlessBird(Bird):
     # any particularly flightless logic here

class Ostrich(FlightlessBird):
     # ostrich logic

seems an invitation to difficulty. My analogy will soon break, but 
some birds build nests and sing, others, no so much, etc. Flat is soon 
to give way to deeply nested.


I also tried to delete the inherited Bird.fly method within 
Ostrich.__init__, but

class Ostrich(Bird):
     def __init__(self):
         del self.__dict__['fly']

raises a KeyError, whereas

     def __init__(self):
         del Ostrich.__dict__['fly']

raises:
TypeError: object does not support item deletion


Do I have the syntax of the last approach wrong? Or is there no way to 
remove a method from a class? If the latter, what to do about 
flightless fowl?

Thanks and best,

Brian vdB



More information about the Tutor mailing list