Access to static members from inside a method decorator?

glen.coates.bigworld at gmail.com glen.coates.bigworld at gmail.com
Thu Oct 5 17:18:19 CEST 2006


Bruno Desthuilliers wrote:
> glen.coates.bigworld at gmail.com wrote:
> > I'm developing a library at the moment that involves many classes, some
> > of which have "exposed" capabilities.  I'm trying to design a nice
> > interface for both exposing those capabilities, and inspecting
> > instances to find out what capabilities they have.
> >
> > At the moment, I'm leaning towards a superclass (Exposed) that defines
> > a static method which is a decorator (expose) such that any derived
> > class can mark a method with @Exposed.expose and it will then be later
> > returned by getExposedMethods(), a la:
> >
> > class Exposed:
> >   @staticmethod
> >   def expose( f ):
> >     ...
> >
> >   def getExposedMethods( self ):
> >     ...
> >
> > class Person( Exposed ):
> >   @Exposed.expose
> >   def talk( self, ... ):
> >     ...
> >
> > I'm trying to implement the decorator by having it populate a static
> > member list of whatever class it's in with a reference to the method.
> > getExposedMethods() would then return the contents of each of those
> > lists from itself back to Exposed in the class hierarchy.  The first
> > problem was that having a reference to the method (i.e. talk()) does
> > not allow you to get a reference to the enclosing class (I had hoped
> > im_class would lead me there).
>
> Not yet. When your decorator is called, the class object is not yet
> created, and what you are decorating is a plain function.
>
> > The real hiccup was that explicitly
> > passing the class as an argument to the decorator generates a undefined
> > global name error, presumably because at that point of execution the
> > class object hasn't been fully created/initialised.
>
> Exactly.
>
> > So how can this be done?
>
> The simplest thing is to use a two-stages scheme : mark the functions as
> exposed, then collect them:
>
> def expose(func):
>   func._exposed = True
>   return func
>
> def exposed(obj):
>   return callable(obj) and getattr(obj, '_exposed', False)
>
> class Exposing(object):
>   @classmethod
>   def get_exposed_methods(cls):
>     try:
>       exposeds = cls._exposed_methods
>     except AttributeError:
>       exposeds = []
>       for name in dir(cls):
>         obj = getattr(cls, name)
>         if exposed(obj):
>           exposeds.append(obj)
>       cls._exposed_methods = exposeds
>     return exposeds
>
> class Parrot(Exposing):
>   @expose
>   def parrot(self, what):
>     return "%s says %s" % (self, str(what))
>
>
>
> HTH
> --
> bruno desthuilliers
> python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
> p in 'onurb at xiludom.gro'.split('@')])"

Thanks Bruno.  I came up with a similar solution today at work, which
involves an 'init' method which is called at the bottom of each module
that defines subclasses of Exposed and sets up static mappings for the
exposed methods.  I guess my solution is slightly less elegant because
it requires this ugly explicit init call outside the classes that it
actually deals with, however it is more efficient because the dir()
pass happens once on module load, instead of every time I want the list
of exposed methods.

Thanks for the help though,
Glen




More information about the Python-list mailing list