[Python-Dev] PEP 318 - posting draft

Phillip J. Eby pje at telecommunity.com
Wed Mar 24 13:17:16 EST 2004


At 07:40 AM 3/24/04 -0800, Guido van Rossum wrote:
> > > But while you're at it, please add to the PEP that I don't like the
> > > idea of class decorators.  I think they don't solve a real problem,
> > > unlike function decorators, and I think that making classes and
> > > functions more similar just adds confusion.
> >
> > I disagree.  There's definitely a use case for something less permanent
> > than a metaclass that gets a reference to a class immediately after
> > creation but before it ends up in the module namespace.  For example,
> > ZopeX3 interfaces and PyProtocols interfaces both use sys._getframe()
> > introspection to add a temporary metaclass so that they can declare
> > that a class supports (or does not support) a particular set of
> > interfaces from the class body itself.  Using the [] syntax to decorate
> > the class would deprecate these sorts of nasty hacks.
>
>But the use cases are certainly very *different* than those for
>function/method decorators, and should be spelled out separately.

Class decorators provide a mechanism that is of greater or equal power to 
metaclasses, but more explicit (you don't have to trace down the entire 
inheritance tree to find them, and they call attention to their specialness 
more) and more combinable.  It is *much* easier to create and chain 
co-operative class decorators, than it is to create and chain combinable 
metaclasses.

It could perhaps be argued that the difficulty with combining metaclasses 
is that Python does not automatically resolve the "inheritance of metaclass 
constraints" as described in the "Putting Metaclasses to Work".  If Python 
did this, then decorators could be implemented by adding them as base 
classes.  However, this would lead to all sorts of interesting pollution in 
__bases__ and __mro__, unless there was magic added to filter the 
decorators back out.

Indeed, we can see this today in systems like Zope's interface metaclasses, 
which have to deal with the artificial 'Interface' instance that is used 
for subclassing.  Granted, today you can use an explicit __metaclass__, but 
it's ugly and provides no way to cleanly combine metaclasses.  I suspect 
that a close look at metaclass usage in today's Python would show that most 
uses are complicated and error-prone ways to emulate class decorators!

So, speaking as an infamous metaclass hacker myself <0.5 wink>, I would say 
that if Python had to choose between having the __metaclass__ syntax and 
using class decorators, I'd go for the decorators, because they're much 
easier to write and use, and harder to screw up, due to the relative 
simplicity and absence of dead chicken-waving.

That's not to say that I'd want to abandon the underlying system of classes 
having metaclasses, just that I'd ditch the '__metaclass__  + 
__new__(meta,name,bases,dict) + super(X,meta).__new__(...)' way of spelling 
them.  Indeed, the spelling is a pretty compelling argument by 
itself.  Here's a sketch of a metaclass that emulates a class decorator:

class AbstractDecoratorClass(type):
     def __new__(meta,name,bases,cdict):
         old = 
super(AbstractDecoratorClass,meta).__new__(meta,name,bases,cdict)
         return meta.decorate(old)

     def decorate(klass,inputclass) [classmethod]:
         raise NotImplementedError


class MyDecoratorClass(AbstractDecoratorClass):

     def decorate(klass,inputclass) [classmethod]:
         # XXX do something here
         return inputclass


class MyDecorator(object):
     __metaclass__ = MyDecoratorClass


class Something(MyDecorator):
     # ...

Whew!  That's a ton of boilerplate, especially when you consider that it 
doesn't support parameterized decorators, pollutes __bases__/__mro__, 
requires non-trivial effort to combine with other decorators, and is 
seriously error-prone.  For example, depending on what my 'decorate' method 
does, it might break when applied to the 'MyDecorator' instance, requiring 
the addition of an 'if' block to handle that special case.




More information about the Python-Dev mailing list