Coding an extendable class

Peter Otten __peter__ at web.de
Wed Dec 31 00:12:28 CET 2003


Tobias Pfeiffer wrote:

> I want to write a package of modules that deal with mathematical
> graphs. So my plan is to have a main.py file where the basic operations
> are done, like reading the file and creating an adjacence list and all
> that. In this main.py file, there is created a Graph class with several
> methods, such as deg(v) or delvertex(v).
> And then, for all of the other things one can do with a graph, I want
> to code other modules, e.g. a file euler.py for finding an Euler way
> through the graph, that extends the class by the method eulerway(). I
> know that I can do something like
> 
> # graphtools/euler.py
> import main
> class Graph(main.Graph):
>     def eulerway(self):
>     [...]
> 
> and then the Graph class imported from euler.py will have both the old
> and the new methods. But what can I do if I want the end user to be
> able to combine several modules and I don't know in which order he will
> do? For example, by
>   import graphtools.main, graphtools.hamilton
> I can do the thingy described above, but what is with something like
>   import graphtools.hamilton, graphtools.euler
> ? In that case I want the class to have all of the methods defined in
> the modules. How do I realize that in the best way?

#__init__.py
class Graph(object):
    def deg(self, v):
        # your code

#euler.py
class EulerMixin(object):
    def eulerway(self):
        # your code

#hamilton.py
class HamiltonMixin(object):
    def whatever(self):
        # your code

The above are all in the graphtools package directory. 
Now a sample usage:

#application.py
import graphtools
from graphtools import euler, hamilton

class Graph(graphtools.Graph, euler.EulerMixin, hamilton.HamiltonMixin):
    pass

The XXXMixin classes are not for standalone use, they should only call but
not override the Graph methods. As long as the different mixins are
orthogonal, i. e. do not affect each other all should be fine.

Alternatively you can derive the hamilton/euler variants from
graphtools.Graph. You must then design the different classes with
cooperation in mind, as demonstrated below with three initialization
routines which are assumed to be run only once:

#__init__.py
class Graph(object):
    def __init__(self):
        self.init()
    def init(self):
        print "init main"
    def deg(self, v):
        print "deg"

#euler.py
import graphtools
class EulerGraph(graphtools.Graph):
    def eulerway(self):
        print "eulerway"
    def init(self):
        print "init euler"
        super(EulerGraph, self).init()

#hamilton.py
import graphtools
class HamiltonGraph(graphtools.Graph):
    def whatever(self):
        print "whatever"
    def init(self):
        print "init hamilton"
        super(HamiltonGraph, self).init()

#usegraphtools.py
import graphtools
from graphtools import euler, hamilton


class Graph(euler.EulerGraph, hamilton.HamiltonGraph):
    pass

g = Graph()
g.eulerway()
g.whatever()
g.deg(1)

Output:

init euler
init hamilton
init main
eulerway
whatever
deg

Peter





More information about the Python-list mailing list