Need advice on subclassing code

R

Rusty Shackleford

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:

class C_1_1(C):
"""Creates a x=1 and y=1 class"""
def __init__(self):
C.__init__(self, 1, 1)

class C_1_2(C):
"""Creates a x=1 and y=2 class"""
def __init__(self):
C.__init__(self, 1, 2)

99% of the specific classes do the exact same thing. For a tiny few,
the class definition looks like this:

class C_3_5(C):
"""Creates a x=3, y=5 class."""
def __init__(self):
C.__init__(self, 3, 5)

def foo(self):
"""Redefine the default C.foo() function."""
return 99

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

Thanks for the help.
 
W

wittempj

Would the approach of using a switch to decide to instatite which class
good for you, like:

py> class C:
py. name = 'C'
py.
py> class D:
py. name = 'D'
py.
py> switch = { (1, 1): C, (1,2): D }
py> x = 1
py> y = 2
py> c = switch[(x,y)]()
py> print c.name
D
py>
 
B

bruno at modulix

Rusty said:
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
 
K

Kent Johnson

Rusty said:
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.
Is this the best solution? Is there some way of doing a default vs.
non-default deal, without having to manually hardcode all the different
possible subclasses?

How are you instantiating the correct class? You should be able to provide a default behaviour. For example if the classes are all defined in module C you could have a factory like this:

import C
def makeC(x, y):
subtype = 'C_%d_%d' % (x, y)
cls = getattr(C, subtype, C.C)
return cls(x, y)

Then in module C just define the subtypes you need to specialize; all other values of x and y will get the base class C.C.

Kent
 
M

Michael Spencer

Kent said:
How are you instantiating the correct class? You should be able to provide a default behaviour. For example if the classes are all defined in module C you could have a factory like this:

import C
def makeC(x, y):
subtype = 'C_%d_%d' % (x, y)
cls = getattr(C, subtype, C.C)
return cls(x, y)

Then in module C just define the subtypes you need to specialize; all other values of x and y will get the base class C.C.

Kent

Or, if you actually want different classes for each set of parameters (say for
debugging or introspection), you could compose the default ones on the fly:


import C
def makeC(x, y):
subtype = 'C_%d_%d' % (x, y)
cls = getattr(C, subtype, None)
if not cls:
# No specialized class found, so compose a default
# This requires C.C to be a new-style class
cls = type(subtype, (C.C,), {"__autogenerated__": True})
return cls(x, y)

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top