Need advice on subclassing code

bruno at modulix onurb at xiludom.gro
Tue Nov 15 11:33:03 EST 2005


Rusty Shackleford wrote:
> Hi --
> 
> We have some code that returns an object of a different class, depending
> on some parameters.  For example:
> 
> if param x is 1 and y is 1, we make an object of class C_1_1.
> if param x is 1 and y is 2, we make an object of class C_1_2.
> 
> C_1_1 and C_1_2 share a common C ancestor, and in practice may be
> identical, but theoretically, could have the same function name with two
> different implementations underneath.
> 
> We have a file where all the C_X_Y classes are defined.  It looks sort
> of like this:
> 
(snip)

> 99% of the specific classes do the exact same thing.  For a tiny few,
> the class definition looks like this:
> 
(snip same code with minor differences...)
>
> The reason for this is that we want to allow different classes to do
> non-standard behavior.  In practice, however, it turns out that most of
> the time, we don't need anything special.
> 
> Is this the best solution? 

No, of course - but I guess you knew it already !-)

> Is there some way of doing a default vs.
> non-default deal, without having to manually hardcode all the different
> possible subclasses?

Here are the pieces of the puzzle:
- A dict is usually the best choice for lookups.
- A tuple can serve as key for a dict.
- A (reference to) a class object can be stored in a dict (or the name
of the class, as a string).
- the get() method of a dict allow for an optional default value to be
use if the requested key is not found

And here's a first go:

def get_object(x, y):
  specials = {
    (1, 2): C_1_2,
    (33, 42): C_33_42,
  }
  # assume class C is the default class
  klass = specials.get((x, y), C)
  return klass()

Now if you store the class names as strings, ie :


  specials = {
    (1, 2): "C_1_2",
    (33, 42): "C_33_42",
  }

you can use a config file (ini, XML, Yaml, or even plain old python) to
store the 'specials' mapping and the default class name, and have
get_object() read from that config file. The trick is to get the class
from the class's name, which is solved with getattr():

def get_object(x, y):
  specials = {
    (1, 2): "C_1_2",
    (33, 42): "C_33_42",
  }
  # assume class 'C' is the default class
  class_name = specials.get((x, y), "C")

  # from class name to class:
  klass = getattr(module_where_classes_live, class_name)
  return klass()


I think you should be able to solve your problem with this.

A last thing: the name of the module storing the classes can also be
stored in a conf file. Use __import__() to get the module object from
it's name.


HTH
-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb at xiludom.gro'.split('@')])"



More information about the Python-list mailing list