updates to PEP 318 from Kevin Smith, including PEP title

This commit is contained in:
David Goodger 2003-06-10 04:29:48 +00:00
parent 5cf7e0227a
commit a2339f1b61
2 changed files with 86 additions and 24 deletions

View File

@ -117,7 +117,7 @@ Index by Category
S 314 Metadata for Python Software Packages v1.1 Kuchling S 314 Metadata for Python Software Packages v1.1 Kuchling
S 315 Enhanced While Loop Carroll S 315 Enhanced While Loop Carroll
S 317 Eliminate Implicit Exception Instantiation Taschuk S 317 Eliminate Implicit Exception Instantiation Taschuk
S 318 Function Modifier Syntax Smith S 318 Function/Method Decorator Syntax Smith
S 754 IEEE 754 Floating Point Special Values Warnes S 754 IEEE 754 Floating Point Special Values Warnes
Finished PEPs (done, implemented in CVS) Finished PEPs (done, implemented in CVS)
@ -328,7 +328,7 @@ Numerical Index
S 315 Enhanced While Loop Carroll S 315 Enhanced While Loop Carroll
SD 316 Programming by Contract for Python Way SD 316 Programming by Contract for Python Way
S 317 Eliminate Implicit Exception Instantiation Taschuk S 317 Eliminate Implicit Exception Instantiation Taschuk
S 318 Function Modifier Syntax Smith S 318 Function/Method Decorator Syntax Smith
SR 666 Reject Foolish Indentation Creighton SR 666 Reject Foolish Indentation Creighton
S 754 IEEE 754 Floating Point Special Values Warnes S 754 IEEE 754 Floating Point Special Values Warnes

View File

@ -1,5 +1,5 @@
PEP: 318 PEP: 318
Title: Function Modifier Syntax Title: Function/Method Decorator Syntax
Version: $Revision$ Version: $Revision$
Last-Modified: $Date$ Last-Modified: $Date$
Author: Kevin D. Smith <Kevin.Smith@theMorgue.org> Author: Kevin D. Smith <Kevin.Smith@theMorgue.org>
@ -8,7 +8,7 @@ Type: Standards Track
Content-Type: text/plain Content-Type: text/plain
Created: 05-Jun-2003 Created: 05-Jun-2003
Python-Version: 2.4 Python-Version: 2.4
Post-History: Post-History: 09-Jun-2003
Abstract Abstract
@ -36,11 +36,16 @@ Motivation
15 lines or so, the translation into a class method is not 15 lines or so, the translation into a class method is not
obvious. A solution to this problem is to move the translation obvious. A solution to this problem is to move the translation
of the method to the same point as the method's declaration. 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 Proposal
Probably the simplest way to place the function that translates Probably the simplest way to place the decorator that translates
an instance method to a class/static method is illustrated in the an instance method to a class/static method is illustrated in the
code below. code below.
@ -58,7 +63,7 @@ Proposal
'def' and the actual name of the method is simply a reference to 'def' and the actual name of the method is simply a reference to
a callable object that returns a new function reference. a callable object that returns a new function reference.
This syntax could also be extended to allow multiple function This syntax could also be extended to allow multiple function
modifiers in the form of a space delimited list as follows: decorators in the form of a space delimited list as follows:
def protected classmethod foo(self): def protected classmethod foo(self):
perform method operation perform method operation
@ -71,46 +76,103 @@ Proposal
While this syntax is simple and easy to read, it does become While this syntax is simple and easy to read, it does become
cluttered and more obscure if you wish to allow arguments to be cluttered and more obscure if you wish to allow arguments to be
sent to the function modifier. sent to the function decorator.
def synchronized(lock) classmethod foo(self): def synchronized(lock) classmethod foo(self):
perform method operation perform method operation
Various syntaxes have been proposed in comp.lang.python. The 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. most common are demonstrated below.
def foo(self) [synchronized(lock), classmethod]: def foo(self) [synchronized(lock), classmethod]:
perform method operation perform method operation
def foo(self) {'pre': synchronized(lock), 'classmethod': True}: def foo(self) (synchronized(lock), classmethod):
""" Skip Montanaro syntax """
perform method operation 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: def foo(self) as synchronized(lock), classmethod:
""" Gerrit Holl syntax """
perform method operation perform method operation
I have a strong preference for the last of the three. The first Since these all appear within the operation of the 'def'
two use syntax that just seems arbitrary which does not help the itself, it makes sense that synchronized, lock, and
user to understand the meaning of it. The third method is very classmethod must exist at the time that the definition
readable and could probably be interpreted easily by those not is compiled. In addition, each of these arguments will be
familiar with Python. 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 Conclusion
The current method of translating an instance method to a class The current method of translating an instance method to a class
or static method is awkward. A new syntax for applying function or static method is awkward. A new syntax for applying function
modifiers should be implemented (proposed syntax shown below). decorators should be implemented (proposed syntax shown below).
def foo(self) as synchronized(lock), classmethod: def foo(self) as synchronized(lock), classmethod:
perform method operation perform method operation
More generally,
def foo(self) as <tuple>:
perform method operation
The proposed syntax is simple, powerful, easy to read, and The proposed syntax is simple, powerful, easy to read, and
therefore preserves those qualities of the Python language. therefore preserves those qualities of the Python language.