Coding an extendable class

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tobias Pfeiffer

    Coding an extendable class

    Hi!

    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.Grap h):
    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.hami lton
    I can do the thingy described above, but what is with something like
    import graphtools.hami lton, graphtools.eule r
    ? 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?

    Bye
    Tobias

    --
    please send any mail to botedesschatten s(at)web(dot)de
  • Jeff Epler

    #2
    Re: Coding an extendable class

    Python sometimes uses "mixin" classes -- see the SocketServer module for
    one example in a core module.

    So main.Graph would be the real graph class, and
    graphtools.hami lton.HamiltonMi xin would be one mixin:
    class MyGraph(main.Gr aph, hamilton.Hamilt onMixin):
    pass
    You could use new.classobj to create a class object with a given list
    of mixins at runtime (untested):
    # In Main
    _graph_classes = []

    def add_mixin(m):
    _graph_classes. append(m)
    global Graph
    Graph = new.classobj("G raph", _graph_classes, {})

    add_mixin(main. _Graph)

    # In each module that defines a new mixin
    class HamiltonianMixi n:
    pass
    main.add_mixin( HamiltonianMixi n)
    however, having the exact nature of main.Graph depend on what other
    modules have been imported is not what most Python users would expect.
    I prefer the solution of having the user list mixins by creating a
    "personaliz ed" graph class.

    Jeff

    Comment

    • Peter Otten

      #3
      Re: Coding an extendable class

      Tobias Pfeiffer wrote:
      [color=blue]
      > 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.Grap h):
      > 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.hami lton
      > I can do the thingy described above, but what is with something like
      > import graphtools.hami lton, graphtools.eule r
      > ? 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?[/color]

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

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

      #hamilton.py
      class HamiltonMixin(o bject):
      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(graphtool s.Graph, euler.EulerMixi n, hamilton.Hamilt onMixin):
      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.Grap h. 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(grap htools.Graph):
      def eulerway(self):
      print "eulerway"
      def init(self):
      print "init euler"
      super(EulerGrap h, self).init()

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

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


      class Graph(euler.Eul erGraph, hamilton.Hamilt onGraph):
      pass

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

      Output:

      init euler
      init hamilton
      init main
      eulerway
      whatever
      deg

      Peter

      Comment

      Working...