Are decorators really that different from metaclasses...

Paul Morrow pm_mon at
Wed Aug 25 05:38:28 CEST 2004

Steven Bethard wrote:

> Paul Morrow <pm_mon <at>> writes:
>>...that they warrant an entirely new syntax?
> [snip]
>>So why don't they share a similar syntax?
>>    class Foo:
>>       """ This is the docstring for class Foo. """
>>       __metaclass__ = M
>>       # body of class goes here
>>    def baz():
>>       """ This is the docstring for function baz. """
>>       __features__ = synchronized, memoized
>>       # body of function goes here.
> As I'm sure someone has already mentioned, this has been brought up before.  
> I'd especially look at:

Well, what I proposed there is more substantial than this, and requires 
a more significant change to the Python system to accomodate.

> That being said, I think the main objection to this syntax is the same 
> objection to any inside-def syntax:  The code inside a funcdef block (with the 
> exception of docstrings, which Guido has repeatedly said he regrets putting 
> there) is executed as part of the /execution/ of the function, not 
> the /definition/.

Yes, but we have the docstring precendent nonetheless.  And I think that 
Guido should stop regretting that decision and start recognizing the 
natural beauty of it.  To allow docstrings at the top of module/class 
bodies, but not at the top of function/method bodies would be 
asymmetrical, and we'd wonder why.  Any alternative means of providing 
docstrings for methods/functions would look like a wart (IMO). 
Especially since the obvious place for them would still be there.

So, no, I for one like docstrings right where they are.  And look at 
what they create a precedent for.

When Python executes a def statement, it binds __doc__ to the docstring 
it finds there.  But what is __doc__?  It's an attribute of the method 
or function object being defined.  Yep.  Its metadata.  It's information 
*about* the method/function.  __doc__ is *not* a local variable of the 
method or function object being defined.

I believe that (virtually) all __xxx__ attributes have this metadata 
aspect (semantics) to them.  When a programmer says

    def foo():
        __author__ = 'Wilma Flintstone'
        __version__ = '0.1'

She does not intend for __author__ nor __version__ to be local variables 
of foo, used somehow by foo in the calculation of its return value.  To 
her they are foo /metadata/ --- attributes of the foo object itself --- 
as they contain information that *describes* foo.

Likewise, when she defines __lt__, __getitem__, __init__, etc. as part 
of a class, they will not typically be called by methods of the class or 
users/consumers/clients of the class [*] the way that 'normal' 
attributes will.  They contain meta info that describes a deeper level 
of class behavior.

And so if all __xxx__ attributes are really metadata attributes, let's 
formally recognize that.  Then, when processing a function/method def, 
after Python binds __doc__ to the function's docstring, it can go ahead 
and bind the other __xxx__ attributes too, making them function 
attributes rather than local variables.  And then after it's finished 
with the function def, if the function defined the __features__ 
attribute, Python can pass the completed function in turn to each 
decorator in the __features__ tuple (or some such).

No asymmetry.  No new syntax.  No warts.

* well, __init__ is a little odd in this respect as subclasses will 
sometimes call a parent's __init__ directly, but that's an exception.


More information about the Python-list mailing list