[Python-Dev] @decoration of classes

Josiah Carlson jcarlson at uci.edu
Mon Mar 28 21:42:51 CEST 2005


Michael Chermside <mcherm at mcherm.com> wrote:
> 
> Josiah Carlson writes:
> 
>      [... stuff about reST and TeX ...]
> > While I have not used it often, I have done the equivalent of decorating
> > classes; it is as natural (though perhaps not quite as useful initially)
> > as decorating functions,
>      [... stuff about ice cream and sprinkles ...]
> 
> Hmm... the only bit that I found particularly interesting there was the bit
> where you mention that you've used class decorators (without the syntax)
> before.
> 
> What did you use them for? After all, the current state of things is "don't
> bother implementing class decorators because there is no compelling use
> case". If you've got some sample use cases, what were they?

99% of my use cases have been of the form of decorating all of the
methods of a class at once (optionally excluding __init__ and __new__)
using @sync or binding constants [1].


> For my own part, I observe the following. Because a function decorator
> acts after the function object is created, there are limits to what it
> can do to the function. It can add some markup (eg: set properties or
> doc strings). It can "hook" either before or after the function is
> called. Or it can "veto" the function call and do something else
> instead. In the case of function calls, these are pretty much the
> interesting things you would want to do.

Unless one is willing to rewrite the bytecode; in which case things like
Raymond's binding constants decorator or even the inline decorator (that
I found and then lost) are possible and useful.


> Similarly, because a class decorator acts after the class is created
> there are limits on what it can do. It can modify the class object
> (replacing methods and such). It can add markup. It can replace the
> class with another (perhaps a proxy or some such). But most of these
> are things which are more easily done by a metaclass... and all of
> them *can* be done by metaclasses. The only noticable advantage that
> I see to class decorators over metaclasses is that there's a more
> straightforward way to combine them. And I'm not sure that combining
> metaclasses (or class decorators) is something I want to encourage.

Indeed, though people do combine metaclasses (or at least attempt to do
so), often in strange, wonderful, and not so wonderful ways.  I actually
learned metaclasses because someone asked a question about combining
them, and I wanted to understand the question (if not answer it).


> So I'm inclined to use different tools for modifying functions and
> modifying classes because the ways you want to modify them are
> different, and decorators are "tuned" to what people normally want
> to do with functions (like simple wrapping) while metaclasses are
> "tuned" to what people normally want to do with classes (like support
> for inheritance.

While one can call what is being done with decorators "simple wrapping",
I believe it goes a bit beyond that.  With properly defined @accepts and
@returns decorators, certainly one can perform runtime validation of
call/return, but with a proper validation mechanism, one can do
compile-time type inference and call type validation/verification
(PyChecker with types, not just number of arguments).  This kind of
thing would give us the (desired by some) optional typing information
for passed and returned arguments.

Of course none of the above is a new idea, but I'm pointing it out so
that we remember that there already exists a mechanism for doing this
without further syntax changes to the language (someone once offered
"def f(int:foo=3)" or some such, and this along with may other things
are possible with decorators).

As a side-note, I personally think of function/method decoration as a
kind of subclassing of a function (as I have mentioned here before[2]);
and if it were treated as such (with an attribute that references the
previous function/method), one wouldn't need to copy __doc__, __name__,
etc., attributes onto certain decorated functions.


As for what most people use metaclasses for, I don't know, I try not to
use metaclasses if possible (I haven't had a _compelling_ need so far),
and don't use class decoration very often either.


> But a few *good* use cases would change my mind.

As I have said from the beginning, I don't believe any of my use cases
are compelling, as I don't believe that sprinkles on a banana split are
compelling.

I also don't believe that someone is going to come forward with a
compelling use case when compared against function/method decorators
(like PyObjC wrapping, @accepts, @returns, @dispatch, @memoize,
@synchronize, @classmethod, @staticmethod, ...), as I don't believe that
even metaclasses are as compelling as function/method decoration.

With that said; if it is there, people will use it.  Someone will even
post on their blog about how it is the best thing ever, or even how it
ruined the language.  So be it.

In any case, I've spent more time writing emails about this particular
topic than I will ever see returned by using class decoration syntax
myself (over some equivalent method), so this is probably my last email
on the subject.


 - Josiah



[1] - Raymond's recipie for binding constants at compile time.
      A user also provides a metaclass version, but I prefer the class
      decoration.
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277940

[2] - [Python-Dev] decorator support
   http://mail.python.org/pipermail/python-dev/2004-September/048631.html


More information about the Python-Dev mailing list