On Sep 17, 4:56 pm, Lee Harr <[EMAIL PROTECTED]> 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 .... > > import random > > def weight(value): > def set_weight(method): > method.weight = value > return method > return set_weight > > class A(object): > def actions(self): > 'return a list of possible actions' > > return [getattr(self, method) > for method in dir(self) > if method.startswith('action_')] > > def action(self): > 'Select a possible action using weighted choice' > > actions = self.actions() > weights = [method.weight for method in actions] > total = sum(weights) > > choice = random.randrange(total) > > while choice> weights[0]: > choice -= weights[0] > weights.pop(0) > actions.pop(0) > > return actions[0] > > @weight(10) > def action_1(self): > print "A.action_1" > > @weight(20) > def action_2(self): > print "A.action_2" > > a = A() > a.action()() > > The problem I have now is that if I subclass A and want to > change the weighting of one of the methods, I am not sure > how to do that. > > One idea I had was to override the method using the new > weight in the decorator, and then call the original method: > > class B(A): > @weight(50) > def action_1(self): > A.action_1(self) > > That works, but it feels messy. > > Another idea was to store the weightings as a dictionary > on each instance, but I could not see how to update that > from a decorator. > > I like the idea of having the weights in a dictionary, so I > am looking for a better API, or a way to re-weight the > methods using a decorator. > > Any suggestions appreciated. > > _________________________________________________________________ > Explore the seven wonders of the > worldhttp://search.msn.com/results.aspx?q=7+wonders+world&mkt=en-US&form=QBRE
What about a function, 'reweight', which wraps the original, and sets a weight on the wrapper? def reweight(value): def reset_weight(method): [EMAIL PROTECTED](method) #optional def new_method( *ar, **kw ): return method( *ar, **kw ) new_method.weight = value return new_method return reset_weight Call like this: class B(A): action_1= reweight( 50 )( A.action_1 ) You could pass them both in to reweight with two parameters: class B(A): action_1= reweight( 50, A.action_1 ) It's about the same. Variable-signature functions have limits. Otherwise, you can keep dictionaries by name, and checking membership in them in superclasses that have them by hand. Then you'd need a consistent name for the dictionary. That option looks like this (unproduced): class A: __weights__= {} @weight( __weights__, 10 ) ... @weight( __weights__, 20 ) ... class B( A ): __weights__= {} #new instance so you don't change the original @weight( __weights__, 50 ) ... B.__weight__ could be an object that knows what it's overriding (unproduced): class A: weights= WeightOb() #just a dictionary, mostly @weights( 10 ) ... @weights( 20 ) ... class B( A ): weights= WeightOb( A.weights ) #new, refs "super-member" @weights( 50 ) ... If either of the last two options look promising, I think I can produce the WeightOb class. It has a '__call__' method. -- http://mail.python.org/mailman/listinfo/python-list