[Tutor] Restricting the type of passed-in objects

Roeland Rengelink r.b.rigilink@chello.nl
Mon, 14 May 2001 09:04:14 +0200


VanL wrote:
> 
> Roeland Rengelink wrote:
> 

[snipped some of my own ramblings]

> 
> Here is how I came to this project:
> 
> I was thinking about writing a faq generator and maintainer for my work.  While
> thinking about the problem, it occurred to me that a faq could be easily
> represented by a tree of faqEntry objects.  Then I could also build into each
> entry the knowledge of how to render itself in various formats (html, text,
> whatever).  Then I could just call faq.render() on the root of the tree and it
> would recursively call itself to render the whole thing, including all the numbers
> 
> and hyperlinks (because the relationships would be defined by each entry's
> position in the tree).
> 
> After I started to work on that problem (and being a data structures junkie -- I
> just think they are cool) it seemed to me that it would be much better to write a
> general tree class and inherit from it.  Then, I started to think how I could make
> 

Being a data structure junkie myself I can sympathize. And there is
definitely something elegant about trees, especially about the way you
can implement various operations by recursive decent.

Trees are also very frustrating to implement in Python. Not because it
is difficult, but because it's so easy to do the same thing more
efficiently with lists or dictionaries.

For example. In a related thread Tim showed a simple BST tree with two
operations
insert() and traverse(). A far more efficient implementation of that
tree is:

import bisect
class BST_tree:
    def __init__(self):
        self.data = []

    def insert(self, value):
        index = bisect.bisect_left(self.data, value)
        if index < len(self.data) and value == self.data[index]:
            raise KeyError("%r allready in tree" % value)
        self.data.insert(index, value)

    def traverse(self, visitor):
        for value in self.data:
            visitor(value)

i.e. just a list under the hoods.

> that tree class be as general as possible, so that I could use it in the future to
> 
> represent different types of trees.

I think this may be a common beginners mistake in OO design. I certainly
frequently made (make) it myself. It seems `natural' to make your base
class as general as possible so you can easily inherit from it when you
want a special version of that base class. However, it is much more
fruitful to think of inheritance in terms of 

1. extending common functionality
The base class provides the implementation of those operations that all
child classes have in common. Such a base class will in general be small
and may be quite useless by itself.

2. implementing the common interface
The base class defines the inteface, and the chilren provide various
implementations
of that interface. Such a base class will be useless by itself, but the
fact that something inherits from it provides valuable information to
the user

Trying to predict in what way a base class will be usable for its
children is what makes it so incredibly hard to design reusable class
hierarchies top-down.

I.e. it is not clear to me whether your faqTree is going to be
- an instance of some general tree object
- a child class extending the functionality of a more abstract tree
- something that just uses a tree for internal representation.

> And thus we are here.  If my faq-o-matic works like I hope, I think it would be a
> pretty cool little hack -- It would be the first thing I would consider neat
> enough to submit to Useless Python.
> 

I don't want to discourage you from investigating abstract data
structures in Python.
It's fun and a great way to learn about one aspect of programming. Maybe
a fruitfull approach may be to first write a FaqTree class:

class FaqTree:
    ...

my_faq = FaqTree(...)
..test that all faq operations work on the my_faq object..

and then try to move tree-like functionality from FaqTree to some more
abstract Tree class

class Tree:
    ...
class FaqTree(Tree):
    ...

my_faq = FaqTree(...)
..test that all faq operations work on the my_faq object..

or, maybe

class Tree:
    ...
class Faq:
    def __init__(...)
        self.data = Tree()

my_faq = Faq(...)
..test that all faq operations work on the my_faq object..

It would be great if, by writing a Faq class, you end up with both a Faq
class and a Tree 
class. But even if you don't get the Tree, you would still have the Faq.

Hope this helps,

Roeland

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

-- 
r.b.rigilink@chello.nl

"Half of what I say is nonsense. Unfortunately I don't know which half"