Access to static members from inside a method decorator?

glen.coates.bigworld at gmail.com glen.coates.bigworld at gmail.com
Fri Oct 6 05:18:12 CEST 2006


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, glen.coates.bigworld at 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




More information about the Python-list mailing list