decorator and API

Aaron "Castironpi" Brady castironpi at gmail.com
Wed Sep 17 19:45:40 EDT 2008


On Sep 17, 6:09 pm, "Aaron \"Castironpi\" Brady"
<castiro... at gmail.com> wrote:
> On Sep 17, 4:56 pm, Lee Harr <miss... at hotmail.com> wrote:
>
>
>
> > I have a class with certain methods from which I want to select
> > one at random, with weighting.
(snip)
>
> > 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.
>
> 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 ) ...

Lee,

Probably overkill.   Here's a solution like above.

class WeightOb( object ):
    def __init__( self, *supers ):
        self.weights= {}
        self.supers= supers
    def set( self, weight ):
        def __callset__( fun ):
            self.weights[ fun.func_name ]= weight
            return fun
        return __callset__
    def reset( self, weight, fun ):
        self.weights[ fun.func_name ]= weight
        return fun
    #search parent 'weight' objects
    #return 'child-most' weight of 'name'
    def get_weight( self, name ):
        if name in self.weights:
            return self.weights[ name ]
        else:
            for x in self.supers:
                try:
                    return x.get_weight( name )
                except KeyError: #not found
                    pass
            raise KeyError
    #returns a dictionary mapping bound instances to weights
    #(hence the second parameter)
    def contents( self, inst ):
        d= {}
        for x in reversed( self.supers ):
            d.update( x.contents( inst ) )
        d.update( dict( [
( getattr( inst, k ), v ) for k, v in self.weights.iteritems( ) ] ) )
        return d


class A( object ):
    weights= WeightOb( )
    @weights.set( 10 )
    def action_1( self ):
        print 'action_1'
    @weights.set( 20 )
    def action_2( self ):
        print 'action_2'
    #WeightOb.contents needs to know which instance to bind
    #functions to.  Get weights from an instance that has them.
    def getweights( self ):
        return self.weights.contents( self )

class B( A ):
    weights= WeightOb( A.weights )
    action_2= weights.reset( 50, A.action_2 )

a= A()
b= B()
print a.weights.get_weight( 'action_1' )
print a.weights.get_weight( 'action_2' )
print b.weights.get_weight( 'action_1' )
print b.weights.get_weight( 'action_2' )
print a.getweights( )
print b.getweights( )


/Output:

10
20
10
50
{<bound method A.action_2 of <__main__.A object at 0x00A04070>>: 20,
<bound meth
od A.action_1 of <__main__.A object at 0x00A04070>>: 10}
{<bound method B.action_2 of <__main__.B object at 0x00A04090>>: 50,
<bound meth
od B.action_1 of <__main__.B object at 0x00A04090>>: 10}



More information about the Python-list mailing list