On Thu, 18 Sep 2008 02:26:29 +0430, Lee Harr wrote: > I have a class with certain methods from which I want to select one at > random, with weighting. > > The way I have done it is this ....
[snip] You are coupling the weights, the actions, and the object which chooses an action all in the one object. I find that harder to wrap my brain around than a more loosely coupled system. Make the chooser independent of the things being chosen: def choose_with_weighting(actions, weights=None): if weights is None: weights = [1]*len(actions) # equal weights # Taken virtually unchanged from your code. # I hope it does what you want it to do! assert len(weights) == len(actions) total = sum(weights) choice = random.randrange(total) while choice > weights[0]: choice -= weights[0] weights.pop(0) actions.pop(0) return actions[0] Loosely couple the actions from their weightings, so you can change them independently. Here's a decorator that populates a dictionary with weights and actions: def weight(value, storage): def set_weight(method): storage[method.__name__] = value return method return set_weight Here's how to use it: class A(object): weights = {} def __init__(self): self.weights = self.__class__.weights.copy() @weight(10, weights) def action_1(self): print "A.action_1" @weight(20, weights) def action_2(self): print "A.action_2" The class is now populated with a set of default weights, which is then copied to the instance. If you want to over-ride a particular weight, you don't need to make a subclass, you just change the instance: obj = A() obj.weights["action_1"] = 30 method = choose_with_weighting(obj.weights.keys(), obj.weights.values()) getattr(obj, method)() # call the method Hope this helps, -- Steven -- http://mail.python.org/mailman/listinfo/python-list