Nathan Fellman
Nathan Fellman

Reputation: 127538

Aliasing a class in Python

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

Answers (4)

Mauro Bianchi
Mauro Bianchi

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

bobince
bobince

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

Ned Batchelder
Ned Batchelder

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

SilentGhost
SilentGhost

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

Related Questions