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