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

_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to