[Python-Dev] PEP 318 - posting draft (original) (raw)

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