Unification of Methods and Functions

David MacQuigg dmq at gain.com
Thu May 20 14:46:56 EDT 2004


On 19 May 2004 23:26:38 -0700, moughanj at tcd.ie (James Moughan) wrote:
>David MacQuigg wrote:
>> I've made your program, Animals_JM.py at
>> http://ece.arizona.edu/~edatools/Python/Exercises/ the next example
>> *after* Animals_2.  The topic of techniques to make a program robust
>> and maintainable is worth a whole chapter, but it would be a
>> distraction in the introductory chapter.
>> 
>> I would still like to see a way to gain the benefits of both Animals_2
>> and Animals_JM in one program.  My attempts to follow up on
>> suggestions in this discussion have only added complexity, not
>> improved the program.
>
>Simple method - choose a different example.  However, you do not
>appear to be open to this suggestion.

If I were not open to suggestions, I would not be spending all this
time patiently extracting the good suggestions from this long thread,
and putting up with dogmatic statements and personal attacks.  I could
repond by saying most of what I'm reading is hot air, but that would
be equally provocative.  Let's see if we can bring this to a better
conclusion.

I like your example, but not as a *substitute* for Animals_2.  It's
just too complex for non-CIS students at this point in the course.  I
think I understand your concerns about Animals_2.  I think the best
way to deal with those concerns is not by complicating the example, or
by taking out everything that could lead to problems, but rather by
pointing out the problems, and showing subsequent examples that fix
those problems, even at the expense of more complexity.

If you have a simple all-in-one alternative to Animals_2, show me.

Meanwhile, what I have understood as problems and suggested solutions
includes:
1) Class variables like numMammals that are not intended to be
directly altered by the user should be made private variables, by
adding a leading underscore. _numMammals.
2) Direct calls to a function from a parent class (super calls) might
not get updated if a programmer adds a new class in the hierarchy.
Calls like Animal.__init__(self) should be replaced by a general call
to the __init__ function from whatever class is directly above the
current class.
Mammal.__bases__[0].__init__(self)
Note: Calls like Mammal.talk(self), which really *are* intended to use
a function from a specific class, should be left as is.
3) Variables like _numMammals which depend on variables in other
classes could get out-of-sync with those other variables ( e.g. if a
programmer adds a new class and forgets to call __init__).  These
variables could be replaced by functions which re-calculate the
dependent values from the original independent data.
Note: This is a trade-off of simplicity and efficiency vs robustness
against future programmer error.

I've implemented these suggestions in Animals_2c.py at
http://ece.arizona.edu/~edatools/Python/Exercises/

Here is a snippet from one of the classes:

class Animal(object):
    _numAnimals = 0
    def numAnimals():
        return ( Animal._numAnimals +
          Mammal.numMammals() + Reptile.numReptiles() )
    numAnimals = staticmethod(numAnimals)

I've re-defined _numAnimals to hold only the count of Animal
instances.  To get the total count of all animals, I've got a new
function numAnimals.  This function does not walk the entire
hierarchy, as I suspect you might require, but it does add up the
totals from all subclasses directly below Animal.  In each of those
subclasses, we define a function which totals the numbers from all of
its subclasses.  In this way we get a simple recursive re-calculation
of all totals anywhere in the hierarchy, and the only actual data is
the count in each class of instances of that class.

We still have an inter-dependency problem when adding classes to the
hierarchy.  We need to remember to add the appropriate num... function
for the new class to its parent class.  For example, when we added a
Reptile class between Animal and Snake, we modified the function above
to include Reptile.numReptiles() in the total.

We also need to make sure we include *all* children of Reptile in the
new numReptiles function.

class Reptile(Animal):
   -numReptiles = 0
   def numReptiles():
      return ( Reptile._numReptiles +
         Snake.numSnakes() + Lizard.numLizards() )

Oops.  We forgot Geckos !!

To avoid these errors in programming, we may need a function that
automatically searches for subclasses, and calls their num functions.
I'm not sure how to do this without making it excessively complex.
Suggestions will be appreciated.

-- Dave




More information about the Python-list mailing list