Decorator metaclass
Maric Michaud
maric at aristote.info
Fri May 23 01:39:29 EDT 2008
Le Friday 23 May 2008 04:28:22 thomas.karolski at googlemail.com, vous avez
écrit :
> Hi,
> I would like to create a Decorator metaclass, which automatically
> turns a class which inherits from the "Decorator" type into a
> decorator.
> A decorator in this case, is simply a class which has all of its
> decorator implementation inside a decorator() method. Every other
> attribute access is being proxied to decorator().getParent().
>
> ...
>
> -------------------------------------------------------
> Unfortunately this does not work. The newly defined __init__ method
> inside __new__, does a call to impl(*args, **dargs). However, since
> the HBar.__init__ calls the Decorator.__init__ method, but the
> HBar.__init__ method no longer resides inside HBar, but rather inside
> HBarImpl (which is no longer a subtype of Decorator), the compiler
> complains that Decorator.__init__ is not being called with a Decorator
> instance as its first argument (which is true).
> I tried changing the definition of impl inside __new__ to have
> Decorator as one of its bases, but then for some reason impl(*args,
> **dargs) asks for 4 arguments (just like __new__) and I have no clue
> as to why that happens.
>
> Any help on this?
>
The problem with kind of design is that you must break the rules of class
inheritance, and it seems like a strange idea to implement decorators by
inheritance.
Of course you could do all sort of magic with python, but what is your goal ?
In your example, should the implementation types inherit from each other ?
In that case, do you want to preserve the same semantic for __init__ as in
standard python class (this could be a hard job) ?
This quick fix seems to work with your example, but add extra magic to
automatically call the super __init__ of the parent implementation, this
could be a bad idea, use with caution ! (I still think it's a bad design,
using composition and proxy classes is much more simple and clear)
class DecoratorType(type):
def __new__(cls, name, bases, dct):
# create a new class which will store all of the
implementation
parent_impl_type = bases[0] is object and object \
or bases[0]._impl_type
impl = type('%sImpl'%name,(parent_impl_type,),dict(dct))
dectype = type.__new__(cls, name, bases, {'_impl_type' :
impl })
# update the old class to implement this implementation
def __init__(self, *args, **dargs):
print args, dargs
new_impl = impl(*args, **dargs)
super(dectype._impl_type, new_impl).__init__(*args,
**dargs)
object.__setattr__(self, '_impl', new_impl)
def decorator(self):
return object.__getattribute__(self,'_impl')
def __getattribute__(self, attr):
if attr=="decorator":
return
object.__getattribute__(self,'decorator')
return getattr(object.__getattribute__(
self, 'decorator')(), attr)
dectype.__init__ = __init__
dectype.decorator = decorator
dectype.__getattribute__ = __getattribute__
return dectype
class Decorator(object):
__metaclass__ = DecoratorType
class HBar(Decorator):
def __init__(self, number):
print 'hb:', number
self._number = number
def inc(self):
self._number += 1
def p(self):
print self._number
class HBar2(HBar) :
def __init__(self, number):
print 'hb2:', number
self._hb2 = number
def inc2(self):
self._hb2 += 1
def p2(self):
print self._hb2
hbar = HBar(10)
for each in dir(hbar.decorator()):
print each
hbar.decorator().p()
hbar.decorator().inc()
hbar.decorator().p()
hb2 = HBar2(5)
hb2.p()
hb2.p2()
hb2.inc()
hb2.p()
hb2.p2()
hb2.inc2()
hb2.p()
hb2.p2()
--
_____________
Maric Michaud
_____________
More information about the Python-list
mailing list