[Python-Dev] Class decorators

Phillip J. Eby pje at telecommunity.com
Thu Mar 30 09:06:52 CEST 2006


At 11:09 PM 3/29/2006 -0500, Jack Diederich wrote:
>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

My uses of class decorators don't fit any of your descriptions -- neither 
do Zope's for that matter, at least not the ones I'm familiar 
with.  "implements(IFoo)" doesn't use any class attributes or delete meta 
attributes from the class.  The whole point of using these decorators is to 
*not* interfere with the class by putting metadata in attributes.

This is especially true for PEAK's class decorators, which are used to do 
things like make security declarations about attributes offered by the 
class (see the examples I posted previously in response to Fred's @class 
proposal).


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

This seems to me like a perfectly good place to use a metaclass.  The place 
where metaclasses tend to quickly meet their downfall is in trying to 
support inheritance, especially multiple inheritance.  If you just have a 
bag of data, however, inheritance doesn't enter into it and a metaclass is 
*perfect*.  It doesn't even have to inherit from 'type', it can even be a 
classic class or a function, just as long as it takes a name, bases tuple, 
and dictionary.



>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:
>@tweak_this_class
>class MyClass:
>   namespacey_stuff = ...
>   def class_thing(self, foo): pass

You can do this quite easily now.  Try running this code and see what happens:

     class Tweaker(object):
         def __class__(self, name, bases, cdict):
             print name, bases, cdict
              # put code here that returns something using name,bases,cdict
             return "I'm a string!"

     Tweak = Tweaker()

     class MyClass(Tweak):
         namespacey_stuff = "foo"
         def class_thing(self, foo): pass

     assert MyClass == "I'm a string!"

If what you're making isn't a class, metaclasses work just fine.  The 
return value of the __class__ method shown here will be bound to the name 
'MyClass' when this runs.


>That leaves a class decorator behaving like a function decorator.

They always did, and as far as I know, nobody has proposed they behave 
otherwise.


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

Again, if you don't want a class to be the result, you can do this sort of 
thing quite easily now.




More information about the Python-Dev mailing list