473,395 Members | 2,006 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Access to static members from inside a method decorator?

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). 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.

So how can this be done? It doesn't seem like it's possible to pass a
reference to the enclosing class into the decorator, which in turn
means that static tracking of the list of exposed methods is impossible
(at least, if I want to use decorators).

Any ideas that will enable my initial design, or suggestions for an
elegant, workable alternative would be much appreciated.

Cheers,
Glen

Oct 4 '06 #1
11 1803
gl******************@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 'o****@xiludom.gro'.split('@')])"
Oct 5 '06 #2
Bruno Desthuilliers wrote:
gl******************@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 'o****@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

Oct 5 '06 #3
Le jeudi 05 octobre 2006 17:18, gl******************@gmail.com a écrit*:
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.
You can always replace the need of the init method on classes using a
metaclass.

This demonstrates it with Bruno's expose decorator, but it can be done with
your actual init func too.

In [6]: class m(type) :
...: def __init__(self, *a,**kw) :
...: for name, meth in self.__dict__.items() :
...: if getattr(meth, '_exposed', False) :
...: print 'exposed :', name
...:
...:

In [7]: class a(object):
...: __metaclass__ = m
...: def f(self) :pass
...: @expose
...: def g(self) :pass
...:
...:
exposed : g

In [8]: class b(a) :
...: @expose
...: def h(self) :pass
...:
...:
exposed : h


--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Oct 5 '06 #4
gl******************@gmail.com wrote:
Bruno Desthuilliers wrote:
(snip)
>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))

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,
This is only a problem in a framework-style use.
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.
I think you have missed a point in my solution : the 'collect' pass
happens only once for each class - the first time the
get_exposed_methods is called on the class (or any instance of). It's
then memoized for latter calls.

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Oct 5 '06 #5
Maric Michaud wrote:
Le jeudi 05 octobre 2006 17:18, gl******************@gmail.com a écrit :
>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.

You can always replace the need of the init method on classes using a
metaclass.

This demonstrates it with Bruno's expose decorator, but it can be done with
your actual init func too.

In [6]: class m(type) :
...: def __init__(self, *a,**kw) :
...: for name, meth in self.__dict__.items() :
NB : This will only get methods exposeds in this class - not the one
exposeds in the parent classes...
...: if getattr(meth, '_exposed', False) :
...: print 'exposed :', name
...:
...:
(snip)
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Oct 5 '06 #6
gl******************@gmail.com wrote:
Bruno Desthuilliers wrote:
>>gl******************@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 'o****@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

Oct 5 '06 #7
Thanks for all the help guys ... in almost every way using a metaclass
seems to be the right solution for what I'm trying to do here. I say
almost because there is one thing that is still confusing me: what is
the most elegant way to provide base-class implementations of methods
that are expected to be overriden by some of the derived classes (or in
the case of metaclasses, the classes that either declare __metaclass__
= Exposed or are derived from such classes).

Here's what I've just knocked out:

import sys

class Exposed( type ):

def __init__( cls, *args, **kw ):

# Track marked exposed methods
cls.s_exposedMethods = []
for superclass in cls.__mro__:
for name, meth in superclass.__dict__.items():
if hasattr( meth, "exposed" ):
cls.s_exposedMethods.append( name )

# Add getExposedMethods method
cls.getExposedMethods = lambda self: self.s_exposedMethods
cls.bar = lambda self: sys.stdout.write( "bar\n" )

@staticmethod
def expose( f ):
f.exposed = True
return f
class Process( object ):

__metaclass__ = Exposed

@Exposed.expose
def foo( self ):
pass
def bar( self ):
print "BAR"
pass
class BotProcess( Process ):

@Exposed.expose
def addBots( self ):
pass

p = Process()
p.bar()

#############

The problem here is that the implementation of 'bar' inside
Exposed.__init__ overrides the implementation of bar() in Process,
which makes sense I guess seeing as Exposed.__init__() is called after
the class has been initialised. It's not a problem for
getExposedMethods() seeing as it's not overriden by any derived
classes.

So what is the accepted way of doing this? Do I need two Exposed
classes, one is the metaclass that handles all the static mapping
stuff, and another provides base implementations of methods and is what
is actually derived from? E.g.:

class ExposedMeta( type ):
...

class Exposed( object ):
...

class Process( Exposed ):
__metaclass__ = ExposedMeta
...

class BotProcess( Process ):
...

Hmmm ... that seems a bit ugly too. If I change the assignments in
Exposed.__init__() I guess I can avoid the two-class thing:

cls.getExposedMethods = getattr( cls, "getExposedMethods", lambda
self: self.s_exposedMethods )
cls.bar = getattr( cls, "bar", lambda self: sys.stdout.write( "bar\n"
) )

That's better, but still ugly. Is there a better way?

Thanks for all the help thus far guys,
Glen

Maric Michaud wrote:
Le jeudi 05 octobre 2006 17:18, gl******************@gmail.com a écrit :
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.

You can always replace the need of the init method on classes using a
metaclass.

This demonstrates it with Bruno's expose decorator, but it can be done with
your actual init func too.

In [6]: class m(type) :
...: def __init__(self, *a,**kw) :
...: for name, meth in self.__dict__.items() :
...: if getattr(meth, '_exposed', False) :
...: print 'exposed :', name
...:
...:

In [7]: class a(object):
...: __metaclass__ = m
...: def f(self) :pass
...: @expose
...: def g(self) :pass
...:
...:
exposed : g

In [8]: class b(a) :
...: @expose
...: def h(self) :pass
...:
...:
exposed : h


--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Oct 6 '06 #8
gl******************@gmail.com wrote:
Thanks for all the help guys ... in almost every way using a metaclass
seems to be the right solution for what I'm trying to do here. I say
almost because there is one thing that is still confusing me: what is
the most elegant way to provide base-class implementations of methods
that are expected to be overriden by some of the derived classes (or in
the case of metaclasses, the classes that either declare __metaclass__
= Exposed or are derived from such classes).

Here's what I've just knocked out:
[snip example]
The problem here is that the implementation of 'bar' inside
Exposed.__init__ overrides the implementation of bar() in Process,
which makes sense I guess seeing as Exposed.__init__() is called after
the class has been initialised. It's not a problem for
getExposedMethods() seeing as it's not overriden by any derived
classes.

So what is the accepted way of doing this? Do I need two Exposed
classes, one is the metaclass that handles all the static mapping
stuff, and another provides base implementations of methods and is what
is actually derived from? E.g.:
You define one base type with a custom metaclass and inherit from that. Your
example then becomes:

import sys

class ExposedType( type ):
def __init__( cls, *args, **kw ):
# Track marked exposed methods
cls.s_exposedMethods = []
for superclass in cls.__mro__:
for name, meth in superclass.__dict__.items():
if hasattr( meth, "exposed" ):
cls.s_exposedMethods.append( name )

class Exposed:
__metaclass__ = ExposedType
def getExposedMethods(self):
return self.s_exposedMethods
def bar(self):
print "bar\n"
@staticmethod
def expose( f ):
f.exposed = True
return f

class Process( Exposed):
@Exposed.expose
def foo( self ):
pass
def bar( self ):
print "BAR"
class BotProcess( Process ):
@Exposed.expose
def addBots( self ):
pass

p = Process()
p.bar()

This prints "BAR" as expected.

Peter
Oct 6 '06 #9
no need for all that,i wrote a basic Ajax framework for cherrypy that
features a Ajax.Net feature,exposing functions to JavaScript via
attributes(or in python via decorators),here is a decorator that run
one time(i.e. before running the actual code) and get the name of the
class
Expand|Select|Wrap|Line Numbers
  1. def AddFunction(func):
  2. stack=inspect.stack()
  3. ClsName=stack[1][3]#get the class name from the stack
  4. #now you both have the ClassName and the func object,so you can
  5. populate your list
  6. return func#return the decorated function
  7.  
it use the module inspect,to inspect the stack.

Oct 6 '06 #10
Peter Otten wrote:
gl******************@gmail.com wrote:

You define one base type with a custom metaclass and inherit from that. Your
example then becomes:

import sys

class ExposedType( type ):
def __init__( cls, *args, **kw ):
# Track marked exposed methods
cls.s_exposedMethods = []
for superclass in cls.__mro__:
for name, meth in superclass.__dict__.items():
if hasattr( meth, "exposed" ):
cls.s_exposedMethods.append( name )

class Exposed:
__metaclass__ = ExposedType
def getExposedMethods(self):
return self.s_exposedMethods
def bar(self):
print "bar\n"
@staticmethod
def expose( f ):
f.exposed = True
return f

class Process( Exposed):
@Exposed.expose
def foo( self ):
pass
def bar( self ):
print "BAR"
class BotProcess( Process ):
@Exposed.expose
def addBots( self ):
pass

p = Process()
p.bar()

This prints "BAR" as expected.

Peter
Thanks Peter. Yeah I had thought of that earlier, but wasn't sure if
this is a standard design pattern for what I'm trying to achieve. It
seems ugly to me to use 2 classes when you are essentially describing a
single type. Is the Splat/SplatType pairing really a common design
pattern when trying to use metaclasses in this way?

Also ... as for the 'inspect' based solution, yeah I can see that would
work, but it seems very hacky to me and my gut reaction is to avoid
that kind of thing ...

Cheers,
Glen

Oct 8 '06 #11
gl******************@gmail.com wrote:
Thanks Peter. Yeah I had thought of that earlier, but wasn't sure if
this is a standard design pattern for what I'm trying to achieve. It
seems ugly to me to use 2 classes when you are essentially describing a
single type.
To me both Exposed and ExposedType look more idiomatic than your combined
approach.
Is the Splat/SplatType pairing really a common design
pattern when trying to use metaclasses in this way?
I think so, but look for yourself:

http://www.google.com/codesearch?q=l...nG=Search+Code

Refinements to that query welcome...

Peter
Oct 9 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Neil Zanella | last post by:
Hello, I would like to know whether it is possible to define static class methods and data members in Python (similar to the way it can be done in C++ or Java). These do not seem to be mentioned...
8
by: Jon Slaughter | last post by:
Is there any way to declare a member of a base class to make the itself in the derived class to be static? i.e., I have two classes class Base { protected: char *name;
9
by: Clint | last post by:
Hey all - Excuse the cross-post ... I'm not sure what the appropriate newsgroup would be for this question. I have a question that I'm not quite sure how to ask. For all I know, I have the...
9
by: sonu | last post by:
Hi All, Pls clarify me what is the difference between static member and static method in c. pls some one reply me with Example.
18
by: Joel Hedlund | last post by:
Hi! The question of type checking/enforcing has bothered me for a while, and since this newsgroup has a wealth of competence subscribed to it, I figured this would be a great way of learning...
15
by: Laser Lu | last post by:
I was often noted by Thread Safety declarations when I was reading .NET Framework Class Library documents in MSDN. The declaration is usually described as 'Any public static (Shared in Visual...
2
by: Ahmed | last post by:
Ok i understand the fact that once events are raised they are executed on another thread and have no access to member functions or variables because they are static functions. But i am having...
5
by: Mahendra Kumar Kutare | last post by:
I am trying to implement a webserver with boss-worker model thread pool implementation - I have a header declaration threadpool.h as - typedef struct threadpool_work { void (*routine) ();...
0
by: J. Cliff Dyer | last post by:
On Thu, 2008-11-13 at 11:19 -0600, Chris Mellon wrote: He is using an object. Specifically, he's using a function object. Though perhaps you meant put it into a class. Here are a few essays...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.