Access to static members from inside a method decorator?
Steve Holden
steve at holdenweb.com
Thu Oct 5 14:01:54 EDT 2006
glen.coates.bigworld at gmail.com wrote:
> 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.
>
Surely the right place to handle "collection" is in a metaclass, where
the metaclass's __call__() method can scan the __dict__ and take
appropriate action on the marked methods? That way it's done just once,
at class definition time, as it should be.
regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://holdenweb.blogspot.com
Recent Ramblings http://del.icio.us/steve.holden
More information about the Python-list
mailing list