Revised PEP 318 - Function/Method Decorator Syntax

Bengt Richter bokr at oz.net
Tue Jun 10 18:55:20 EDT 2003


On 10 Jun 2003 12:25:13 GMT, Kevin Smith <Kevin.Smith at sas.com> wrote:

>I have received many comments on this proposal already and have taken 
>them into account in this proposal.  The proposed syntax is still
[...]
>    Instead of placing the decorators in front of the function name,
>    a better place might be after it, as shown below.  The word 'as' is 
>    added simply as a separator to assist in readability.  
>
>        def foo(self) as synchronized(lock), classmethod:
>            perform method operation
>
>    This syntax is quite clear and could probably be interpreted 
>    by those not familiar with Python.  The proposed syntax can be
>    generalized as follows: 
>
>        'def' NAME '(' PARAMETERS ')' ['as' DECORATORS] ':'
>
>    where DECORATORS is a comma-separated list of expressions, 
>    or a tuple.
>
>    Other syntaxes have been proposed in comp.lang.python.  The 
>    most common are demonstrated below.
>
>        def foo(self) [synchronized(lock), classmethod]:
>            perform method operation
>
>        def foo(self) (synchronized(lock), classmethod):
>            perform method operation
>
>        def foo(self) {'pre': synchronized(lock), 'classmethod': True}:
>            perform method operation
>
>    These three forms use syntax that just seems arbitrary and which 
>    does not help the user to comprehend the meaning of it.  In 
>    addition, since the order in which the decorators are applied 
>    may matter, the third, dictionary-style, syntax must be 
>    eliminated.
I disagree with that "must" ;-) Better to say ordering must be specified
by other means. E.g., trivially, you could add 'ordering':('pre','classmethod') to
the above dict.

IMO a list or tuple of decorator functions second-guesses the future too narrowly,
and will create an unnecessary backwards-compatibility constraint. Why not an
identifier for a class with some standard methods that are conventionally
called internally, like .decorate() ? (I'm moving forward from Skip's dict and
my previous variations on dict/dict-workalike objects ;-)

Using a class  with a general __init__(*args,**kw) parameter list will permit
defining builtins for standard decorations and creating customized/derived versions
as well. The list/tuple syntax functionality could easily be implemeted with a class
by putting the elements in the call to the constructor, e.g.,

         'def' NAME '(' PARAMETERS ')' ['as' DECORATORS_CLASS ['(' DECORATORS ')']] ':'

where standard DECORATORS could already be built in to a standard DECORATORS_CLASS,
or a parenthesized sequence could follow, but also allow keyword items. You could specify
DECORATORS exactly as you propose, but now the door would be open to future ideas of
decoration specification.
>    
>Implementation Issues
>
>    In the following example there are two function decorators: 
>    synchronized(lock) and classmethod.  
>
>        def foo(self) as synchronized(lock), classmethod:
>            perform method operation

         def foo(self) as DECORATORS(synchronized(lock), classmethod):
             perform method operation

where DECORATORS would be a builtin standard decoration control class for your kind
of decoration sequences.

>
>    Since these all appear within the operation of the 'def' 
>    itself, it makes sense that synchronized, lock, and 
>    classmethod must exist at the time that the definition 
>    is compiled.  In addition, each of these arguments will be
ISTM this needs clarification. Is this what you mean?

    <def foo source> -> [compile] -> <executable foo def>
    <executable foo def> -> [execute] -> <foo bound to function> # function created by execution of def
    <foo function> -> [decorate] -> <foo bound to modified function>
 
>    evaluated before being applied to the compiled function.
You must be thinking of "compiled function" as the end result of compiling AND executing a definition?
  
>    This means that arguments like synchronized(lock) must 
>    return a descriptor that will be applied to foo.  Therefore, 
>    the code above translates to:
>
>        def foo(self):
>            perform method operation
>        foo = classmethod(<returned-descriptor>(foo))
or
         def foo(self):
             perform method operation
         foo = DECORATORS(synchronized(lock), classmethod).decorate(foo)

this would allow
        USING_MY_LOCK = DECORATORS(synchronized(lock), classmethod)
        ...
        def foo(self) as USING_MY_LOCK:
            pass # foo body

translating to
        ...
        def foo(self):
            pass # foo body
        foo =  USING_MY_LOCK.decorate(foo)
>    
>    In the example above, <returned-descriptor> refers to the 
>    descriptor returned by evaluating synchronized(lock).
>
[...]
>Possible Extensions
>
>    The proposed syntax is general enough that it could be used 
>    on class definitions as well as shown below.
>
>        class foo(object) as classmodifier:
>            class definition here
>
>    However, there are no obvious parallels for use with other
>    descriptors such as property().
>
>
>Conclusion
>
>    The current method of translating an instance method to a class
>    or static method is awkward.  A new syntax for applying function
>    decorators should be implemented (proposed syntax shown below).  
>
>        def foo(self) as synchronized(lock), classmethod:
>            perform method operation
>
>    The proposed syntax is simple, powerful, easy to read, and 
>    therefore preserves those qualities of the Python language.

Is the syntax a frozen mod to the def syntax, or is what comes after 'as'
an arbitrary tuple expression? E.g., would the above be spellable as

	 syncmeth = (synchronized(lock), classmethod)
         def foo(self) as syncmeth:
             perform method operation

Is it reasonable to think of this mechanism as a kind of meta-classes for functions?
Is there some unification that should not be painted out of the future?

Regards,
Bengt Richter




More information about the Python-list mailing list