@decorators

Mark Bottjer mark_bottjer at hotmail.com
Fri Aug 6 13:48:55 EDT 2004


Tor Iver Wilhelmsen wrote:
> I think what he meant was that the decorators in effect make for
> "hidden continuation", e.g.
> 
> @foo
> def fooDecorated():
>     pass
> 
> is like
> 
> @foo def fooDecorated():
>     pass:
> 
> when other line continuations are explicit.

Which is *exactly* why I dislike this syntax so much. I don't mind the 
"@", though it does look a might out-of-place. What I dislike is the 
placement: It relies on setting a "magic state" in the interpreter to 
affect the very next thing at the same indentation level. I can't think 
of any other place in Python where this sort of thing is done. 
Everything else either introduces a new block, or requires bracketing.

Everyone shows the examples like above, but what about the following?

class C:
   # This is a really long comment that has little to do
   # with the following function; it is here only so that
   # the comment wraps. This is a really long comment that
   # has little to do with the following function; it is
   # here only so that the comment wraps over several lines.
   @ staticmethod

   # MAB 20040806113000: Added argument baz.
   # MAB 20040806112957: Added argument bar.
   # MAB 20040806112950: Initial version.
   def static_method_foo( bar, baz):
     pass

Did you catch it? This method *is* decorated, though it is hard to see 
it unless you are really looking for it. Syntax coloring will help, of 
course, but not much, and we shouldn't rely on that anyway.

My concern is that the decorator can be separated from the decorated by 
an arbitrarily large amount of space. Even ONE blank line is enough for 
me to mentally dissociate the decorator from the decorated. Comments 
make it worse. Now, would a sane programmer do this? One would hope not, 
but there is nothing to prevent it--and I've found that the definition 
of "sane" varies widely between programmers.

What I think might work better is to treat these decorators the same way 
we already treat docstrings.

def decorated( a, b, c):
     @classmethod
     @signature( None, a=int, b=float, c=dict)
     @transactional( database)
     """\
     decorated( a, b, c): A thrice-decorated function.

     The silly function does nothing except get "decorated." classmethod
     determines the form of the first argument (class, object, or
     other). signature changes the call behavior, asserting the types
     passed to and returned from the function. Finally, transactional
     causes boilerplate code to be executed before and after the function
     body, ensuring that either all changes to database are applied, or
     none are. Seeing as this function does nothing, this is trivial :).
     """

     pass

Personally, I kind of like the "@" syntax in this form. It still sticks 
out (and IMHO, it *should* stick out, because it is not a normal 
statement), but it also is easier to ignore if you aren't looking for it 
because it is explicitly scoped at the function level.

We already expect metadata--namely, the docstring--to be at the top of 
the function. This simply extends that idea to include other forms of 
metafunctionality. The compiler already looks for metadata at the start 
of functions; the special syntax helps the compiler determine which 
statements need to be handled immediately, and where the function 
implementation starts.

   -- Mark



More information about the Python-list mailing list