[Python-Dev] Class decorators

Jack Diederich jack at performancedrivers.com
Thu Mar 30 06:09:56 CEST 2006

[promted by Phillip Eby's post, but not in response so content snipped]

I think we both want class decorators as a more fine grained substitute
for __metaclass__ (fine grained as in declared per-class-instance instead
of this-class-and-all-its-children).  I can think of three ways class
decorators are used:

1) register pattern, use a class attribute or two to stick the class in
   a lookup table and optionally delete the meta-attribs from the class
2) __init__ pattern, examine the class and maybe munge it based on attribs
3) __new__ pattern, consider the class a namespace and use the attribs
   to generate an essentially new class based on the attribs

(the main difference between 2 and 3 is that the __new__ caseis a
total tear down and rebuild where 2 tends towards tweaks on the parent)

Classes have a unique property in that they are the easiest way to make
little namespaces in python.  Modules require lots of file clutter,
functions as namespaces require digging into the internals, dicts as
namespaces require more finger typing and don't support attribute access.

It turns out I have two use cases for class decorators and didn't even
know it.  One is the 'register' pattern that started this thread.  In
that case I just want to move the metadata outside the class 
(the @register(db_id=20) case) and the rest of the class definition is
honest to goodness overriding of a method or two from the parent class
to change the behavior of its instances.  The other pattern I hadn't thought
of would be a '@namespace' decorator.  A @namespace decorator would strip 
the attribs of all class-like qualities - it would strip the class of all 
descriptor magic (using descriptors, of course!).  I just want a convenient 
bag to stick related items in.

The first time I ever used metaclasses was to make PLY[1] (a SLR parser)
use per-class namespaces for lexers and grammars instead of per-module.
The metaclass chewed through all the class attributes and returned
a class that shared no attributes with the original - each class was 
basically a config file.  The decorator version would be spelled
'@make_a_lexer_class' or '@make_a_grammar_class'.  

PEAK and Zope seem like they do a mix of __init__ and __new__, my current
use cases are just 'notice' (I'm not a user, so feel free to correct).
I like the func-like decorator syntax because I have just a bit of
metadata that I'd like to move outside the class.  PEAK/Zope sounds
like they use classes as a mix of class and namespace.  Their class
decorator would return a hybrid class that has applied the namespace
parts (post processing) to the class parts.  A partly new class.

I'd like that spelled:
class MyClass:
  namespacey_stuff = ...
  def class_thing(self, foo): pass

That leaves a class decorator behaving like a function decorator.  It
is a declaration that the final product (maybe a completely different
thing as in the PLY case) is the result of the tweak_this_class function.

Writing the above certainly helped me clear up my thoughts on the issue,
I hope it hasn't gone and muddied it for anyone else :)


[1] http://savannah.nongnu.org/projects/ply/

More information about the Python-Dev mailing list