192 lines
6.2 KiB
Plaintext
192 lines
6.2 KiB
Plaintext
PEP: 318
|
||
Title: Function/Method Decorator Syntax
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Kevin D. Smith <Kevin.Smith@theMorgue.org>
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Content-Type: text/plain
|
||
Created: 05-Jun-2003
|
||
Python-Version: 2.4
|
||
Post-History: 09-Jun-2003
|
||
|
||
|
||
Abstract
|
||
|
||
The current method for declaring class and static methods
|
||
is awkward and can lead to code that is difficult to understand.
|
||
This PEP introduces possible new syntax which will place the
|
||
translation of instance methods to class/static methods at
|
||
the same point in the code as the method's declaration.
|
||
|
||
|
||
Motivation
|
||
|
||
The current method of translating an instance method into a
|
||
class/static method places the actual translation at a different
|
||
point in the code than the declaration of the method. The
|
||
code below demonstrates this.
|
||
|
||
def foo(self):
|
||
perform method operation
|
||
foo = classmethod(foo)
|
||
|
||
When the method is very short, it is easy to look ahead and see
|
||
that this is a class method. However, if the method is more than
|
||
15 lines or so, the translation into a class method is not
|
||
obvious. A solution to this problem is to move the translation
|
||
of the method to the same point as the method's declaration.
|
||
The proposed syntax, shown in the example below, is discussed
|
||
in the following sections.
|
||
|
||
def foo(self) as synchronized(lock), classmethod:
|
||
perform method operation
|
||
|
||
|
||
Proposal
|
||
|
||
Probably the simplest way to place the decorator that translates
|
||
an instance method to a class/static method is illustrated in the
|
||
code below.
|
||
|
||
def classmethod foo(self):
|
||
perform method operation
|
||
|
||
The code in this example will simply perform the following.
|
||
|
||
def foo(self):
|
||
perform method operation
|
||
foo = classmethod(foo)
|
||
|
||
This syntax does not introduce any new keywords and is completely
|
||
backwards compatible with any existing code. The word between the
|
||
'def' and the actual name of the method is simply a reference to
|
||
a callable object that returns a new function reference.
|
||
This syntax could also be extended to allow multiple function
|
||
decorators in the form of a space delimited list as follows:
|
||
|
||
def protected classmethod foo(self):
|
||
perform method operation
|
||
|
||
which would be equivalent to the current form:
|
||
|
||
def foo(self):
|
||
perform method operation
|
||
foo = protected(classmethod(foo))
|
||
|
||
While this syntax is simple and easy to read, it does become
|
||
cluttered and more obscure if you wish to allow arguments to be
|
||
sent to the function decorator.
|
||
|
||
def synchronized(lock) classmethod foo(self):
|
||
perform method operation
|
||
|
||
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.
|
||
|
||
|
||
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
|
||
|
||
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
|
||
evaluated before being applied to the compiled function.
|
||
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))
|
||
|
||
In the example above, <returned-descriptor> refers to the
|
||
descriptor returned by evaluating synchronized(lock).
|
||
|
||
It could easily be argued that the descriptors should be applied
|
||
in reverse order to make the application of the descriptor look
|
||
more like the resultant code. I tend to prefer this form.
|
||
|
||
def foo(self):
|
||
perform method operation
|
||
foo = <returned-descriptor>(classmethod(foo))
|
||
|
||
In either case, the modified function is bound to the function
|
||
name at compile time.
|
||
|
||
|
||
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.
|
||
|
||
|
||
Copyright
|
||
|
||
This document has been placed in the public domain.
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
sentence-end-double-space: t
|
||
fill-column: 70
|
||
End:
|