[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