[Python-Dev] Class decorators

Jack Diederich jack at performancedrivers.com
Thu Mar 30 03:00:59 CEST 2006


On Wed, Mar 29, 2006 at 07:23:03PM -0500, Phillip J. Eby wrote:
> At 11:07 AM 3/29/2006 -0800, Guido van Rossum wrote:
> >On 3/28/06, Phillip J. Eby <pje at telecommunity.com> wrote:
> > > If we're using Zope 3 as an example, I personally find that:
> > >
> > >      class Foo:
> > >          """Docstring here, blah blah blah
> > >          """
> > >          implements(IFoo)
> > >
> > > is easier to read than:
> > >
> > >      @implements(IFoo)
> > >      class Foo:
> > >          """Docstring here, blah blah blah
> > >          """
> >
> >But the former also smells more of magic.
> 
> My comment above was only about readable *placement* of the decorators, not 
> the actual syntax.  Many approaches to the actual syntax in the body are 
> possible.
> 
> For example, what did you think of Fred Drakes's "@class" proposal?  To 
> specify it formally, one could say that this:
> 
>      @class EXPR
> 
> in a class scope would expand to the equivalent of:
> 
>      locals().setdefault('__decorators__',[]).append(EXPR)
> 
> and is a syntax error if placed anywhere else.  That, combined with support 
> for processing __decorators__ at class creation time, would fulfill the 
> desired semantics without any implicit "magic".
> 

A function decorator takes a function as an argument and returns something
(probably a function and maybe even the very same function).
This is exactly what class decorators should do or we should call them
something else and give them a distinct syntax.

A function decorator is there to replace code like:

def myfunc(a, b, c):
  # half a screen of code
myfunc = mangle(myfunc)

Likewise class decorators would save me from typing

class MyClass:
  # many functions taking half a screen of code each
register(MyClass, db_id=20)

I used to do this with metaclasses but stopped because it requires making
'db_id' a member of the class which is magically noticed by a metaclass
two files away.  Using metaclasses also required gross hacks like checking
for a 'DO_NOT_REGISTER' member for subclasses that wanted to inherit from
a class that had a Register metaclass but didn't want to be registered.
Yuck.

If you want to do lots of Zopeish stuff mostly inside the class write
a decorator that looks for it in the class body.

@zope.find_magic_in_attr('mymagic')
class MyClass:
  mymagic = [] # some long hairy thing

Talking about something other than a decorator or proposing all new
syntax is just going to get this pronounced out of existence.

If-I-wanted-zope-I'd-use-zope-ly,

-jackdied


More information about the Python-Dev mailing list