Reputation: 127538
I am writing a class to implement an algorithm. This algorithm has three levels of complexity. It makes sense to me to implement the classes like this:
class level0:
def calc_algorithm(self):
# level 0 algorithm
pass
# more level0 stuff
class level1(level0):
def calc_algorithm(self):
# level 1 algorithm
pass
# more level1 stuff
class level2(level1):
def calc_algorithm(self):
# level 2 algorithm
pass
# more level2 stuff
Where I expect that calc_algorithm
will be overridden in each class. Depending on a certain commandline option I want to run either level 0, level 1 or level 2 on the data. This is how I call the algorithm:
for offset in itertools.product(*map(xrange, (dim[0] - 1, dim[1] - 1, dim[2] - 1))):
algorithm(offset).calc_algorithm
Where algorithm
is either level0
, level1
or level2
.
The way I'd do it in other languages is:
for offset in itertools.product(*map(xrange, (dim[0] - 1, dim[1] - 1, dim[2] - 1))):
if (level == 0):
level0(offset).calc_algorithm
else:
if (level == 1):
level1(offset).calc_algorithm
else:
level2(offset).calc_algorithm
Is there a Pythonic way to alias a class to refer to another class, so that I could do:
algorithm = (level == 0) and level0 or (level == 1) and level1 or level2
and then call algorithm
as above?
Just for comparison, in Specman, which is an Aspect Oriented language I could write the class like this:
struct algorithm {
level: uint;
// common stuff for all levels
calc_algorithm() is empty;
when (level == 0) {
calc_algorithm() is only {
// level 0 algorithm
};
};
when (level == 1) {
calc_algorithm() is only {
// level 1 algorithm
};
};
when (level == 1) {
calc_algorithm() is only {
// level 1 algorithm
};
};
};
And then once I set the level
struct member, I can use the rest of the class transparently.
Upvotes: 1
Views: 1515
Reputation: 693
Personally, I wouldn't create 3 classes, but one class with 3 different calculation methods, and dinamically change the official calculation method (the calculation interface) as needed. For example:
class algorithm:
def __init__(self, level = 0):
self.level = level
self.calcFunctions = {0: self.calcLevel0, 1: self.calcLevel1, 2:self.calcLevel2}
#initial value for calc function
self.setLevel(level)
def setLevel(self, newlevel):
self.level = newlevel
self.calc = self.calcFunctions[level]
def calcLevel0(self):
"""Level 0 calc algorithm"""
#...
pass
def calcLevel1(self):
"""Level 1 calc algorithm"""
#...
pass
def calcLevel2(self):
"""Level 2 calc algorithm"""
#...
pass
#class in use:
#level (taken from command line in your case)
level = 1
alg = algorithm()
alg.setLevel(level)
alg.calc()
If you don't need to change the calcFunction dinamically during execution, you could also pass level to class constructor
Upvotes: 2
Reputation: 536567
The key is that — unlike in some other languages where classes are ‘special’ and you'd have to have some unusual means of ‘aliasing’ them — in Python, classes are themselves first-class objects which are referenced by perfectly normal variables.
So ‘a’ can be aliased as ‘b’ as simply as saying ‘b=a’.
Is there a Pythonic way to alias a class to refer to another class, so that I could do:
algorithm = (level == 0) and level0 or (level == 1) and level1 or level2
Well yes, that's exactly right and will already work just as you wrote it!
...although modern Python has the if/else expression so today you'd generally say:
algorithm= level0 if level==0 else level1 if level==1 else level2
but then a sequence access would probably be simpler than two conditionals:
algorithm= (level0, level1, level2)[level]
Upvotes: 3
Reputation: 375744
dispatch = {0:level0, 1:level1, 2:level2}
algo = dispatch[offset]() # "calling" a class constructs an instance.
algo.calc_algorithm()
If you like introspection more:
class_name = "level%d" % offset
klass = globals()[class_name]
algo = klass()
algo.calc_algorithm()
Upvotes: 4
Reputation: 319821
Are you looking for something along these lines?
dispatch = {0: level0, 1: level1, 2:level2}
dispatch[offset].calc_algorithm
Keys (and offset
), obviously, could come from command line.
Upvotes: 11