reST foo to the rescue!

This commit is contained in:
David Goodger 2004-08-20 01:14:23 +00:00
parent 08ce24e39a
commit 5ae519ab7d
1 changed files with 148 additions and 167 deletions

View File

@ -17,22 +17,23 @@ Post-History: 09-Jun-2003, 10-Jun-2003, 27-Feb-2004, 23-Mar-2004
WarningWarningWarning WarningWarningWarning
===================== =====================
This is not yet complete. This is still a work-in-progress. Feedback This is not yet complete. This is still a work-in-progress. Feedback
to anthony. Please note that the point of this PEP is _not_ to provide to anthony. Please note that the point of this PEP is _not_ to
an open-slather of plusses and minuses for each syntax, but is instead provide an open-slather of plusses and minuses for each syntax, but is
to justify the choice made. If, in 2.4a3, the syntax is changed, the instead to justify the choice made. If, in 2.4a3, the syntax is
PEP will be updated to match this, complete with the arguments for the changed, the PEP will be updated to match this, complete with the
change. arguments for the change.
Abstract Abstract
======== ========
The current method for transforming functions and methods (for instance, The current method for transforming functions and methods (for
declaring them as a class or static method) is awkward and can lead to instance, declaring them as a class or static method) is awkward and
code that is difficult to understand. Ideally, these transformations can lead to code that is difficult to understand. Ideally, these
should be made at the same point in the code where the declaration transformations should be made at the same point in the code where the
itself is made. This PEP introduces new syntax for transformations of a declaration itself is made. This PEP introduces new syntax for
function or method declaration. transformations of a function or method declaration.
Motivation Motivation
@ -73,7 +74,7 @@ benefits are not as immediately apparent. Almost certainly, anything
which could be done with class decorators could be done using which could be done with class decorators could be done using
metaclasses, but using metaclasses is sufficiently obscure that there metaclasses, but using metaclasses is sufficiently obscure that there
is some attraction to having an easier way to make simple is some attraction to having an easier way to make simple
modifications to classes. For Python 2.4, only function/method modifications to classes. For Python 2.4, only function/method
decorators are being added. decorators are being added.
@ -104,87 +105,84 @@ Class decorations seem like an obvious next step because class
definition and function definition are syntactically similar. definition and function definition are syntactically similar.
The discussion continued on and off on python-dev from February 2002 The discussion continued on and off on python-dev from February 2002
through July 2004. Hundreds and hundreds of posts were made, with people through July 2004. Hundreds and hundreds of posts were made, with
proposing many possible syntax variations. Guido took a list of people proposing many possible syntax variations. Guido took a list
proposals to `EuroPython 2004`_, where a discussion took place. of proposals to `EuroPython 2004`_, where a discussion took place.
Subsequent to this, he decided that for 2.4a2 we'd have the `Java-style`_ Subsequent to this, he decided that for 2.4a2 we'd have the
@decorator syntax. Barry Warsaw named this the 'pie-decorator' `Java-style`_ @decorator syntax. Barry Warsaw named this the
syntax, in honor of the Pie-thon Parrot shootout which was announced 'pie-decorator' syntax, in honor of the Pie-thon Parrot shootout which
about the same time as the decorator syntax, and because the @ looks a was announced about the same time as the decorator syntax, and because
little like a pie. Guido `outlined his case`_ on Python-dev, the @ looks a little like a pie. Guido `outlined his case`_ on
including `this piece`_ on the various rejected forms. Python-dev, including `this piece`_ on the various rejected forms.
.. _EuroPython 2004: .. _EuroPython 2004:
http://www.python.org/doc/essays/ppt/euro2004/euro2004.pdf http://www.python.org/doc/essays/ppt/euro2004/euro2004.pdf
.. _outlined his case: .. _outlined his case:
http://mail.python.org/pipermail/python-dev/2004-August/author.html http://mail.python.org/pipermail/python-dev/2004-August/author.html
.. _this piece: .. _this piece:
http://mail.python.org/pipermail/python-dev/2004-August/046672.html http://mail.python.org/pipermail/python-dev/2004-August/046672.html
.. _Java-style:
.. Java-style:
http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html
On the name 'Decorator' On the name 'Decorator'
======================= =======================
There's been a number of complaints about the choice of the name There's been a number of complaints about the choice of the name
'decorator' for this feature. The major one is that the name is 'decorator' for this feature. The major one is that the name is not
not consistent with it's use in the `GoF book`_. The name 'decorator' consistent with its use in the `GoF book`_. The name 'decorator'
probably owes more to it's use in the compiler area - a syntax tree probably owes more to its use in the compiler area -- a syntax tree is
is walked and annotated. It's quite possible that a better name may walked and annotated. It's quite possible that a better name may turn
turn up. up.
.. GoF book: .. _GoF book:
http://patterndigest.com/patterns/Decorator.html http://patterndigest.com/patterns/Decorator.html
Design Goals Design Goals
============ ============
The new syntax should The new syntax should
* work for arbitrary wrappers, including user-defined callables and * work for arbitrary wrappers, including user-defined callables and
the existing builtins ``classmethod()`` and ``staticmethod()`` the existing builtins ``classmethod()`` and ``staticmethod()``
* work with multiple wrappers per definition * work with multiple wrappers per definition
* make it obvious what is happening; at the very least it should be * make it obvious what is happening; at the very least it should be
obvious that new users can safely ignore it when writing their own obvious that new users can safely ignore it when writing their own
code code
* not make future extensions more difficult * not make future extensions more difficult
* be easy to type; programs that use it are expected to use it very * be easy to type; programs that use it are expected to use it very
frequently frequently
* not make it more difficult to scan through code quickly. It should * not make it more difficult to scan through code quickly. It should
still be easy to search for all definitions, a particular still be easy to search for all definitions, a particular
definition, or the arguments that a function accepts definition, or the arguments that a function accepts
* not needlessly complicate secondary support tools such as * not needlessly complicate secondary support tools such as
language-sensitive editors and other "`toy parser tools out language-sensitive editors and other "`toy parser tools out
there`_" there`_"
* move from the end of the function, where it's currently hidden, to * move from the end of the function, where it's currently hidden, to
the front where it is more `in your face`_ the front where it is more `in your face`_
Andrew Kuchling has links to a bunch of the discussions about
motivations and use cases `in his blog`_. Particularly notable is `Jim
Huginin's list of use cases`_.
.. _toy parser tools out there: .. _toy parser tools out there:
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=mailman.1010809396.32158.python-list%40python.org http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=mailman.1010809396.32158.python-list%40python.org
.. _in your face:
.. in your face:
http://mail.python.org/pipermail/python-dev/2004-August/047112.html http://mail.python.org/pipermail/python-dev/2004-August/047112.html
Andrew Kuchling has links to a bunch of the discussions about motivations
and use cases `in his blog`_. Particularly notable is `Jim Huginin's list
of use cases`_.
.. _in his blog: .. _in his blog:
http://www.amk.ca/diary/archives/cat_python.html#003255 http://www.amk.ca/diary/archives/cat_python.html#003255
.. _Jim Huginin's list of use cases: .. _Jim Huginin's list of use cases:
http://mail.python.org/pipermail/python-dev/2004-April/044132.html http://mail.python.org/pipermail/python-dev/2004-April/044132.html
Current Syntax Current Syntax
============== ==============
@ -206,30 +204,33 @@ without the intermediate assignment to the variable ``func``. The
decorators are near the function declaration. The @ sign makes it decorators are near the function declaration. The @ sign makes it
clear that something new is going on here. clear that something new is going on here.
The decorator statement is limited in what it can accept - arbitrary The decorator statement is limited in what it can accept -- arbitrary
expressions will not work. Guido preferred this because of a `gut feeling`_ expressions will not work. Guido preferred this because of a `gut
feeling`_.
.. _gut feeling: .. _gut feeling:
http://mail.python.org/pipermail/python-dev/2004-August/046711.html http://mail.python.org/pipermail/python-dev/2004-August/046711.html
Syntax Alternatives Syntax Alternatives
=================== ===================
There have been `a large number`_ of different syntaxes proposed - rather There have been `a large number`_ of different syntaxes proposed --
than attempting to work through these individual syntaxes, it's worthwhile rather than attempting to work through these individual syntaxes, it's
to break the syntax discussion down into a number of areas. Attempting to worthwhile to break the syntax discussion down into a number of areas.
discuss `each possible syntax`_ individually would be an act of madness, Attempting to discuss `each possible syntax`_ individually would be an
and produce a completely unwieldly PEP. act of madness, and produce a completely unwieldly PEP.
.. a large number: .. _a large number:
http://www.python.org/moin/PythonDecorators http://www.python.org/moin/PythonDecorators
.. each possible syntax: .. _each possible syntax:
http://ucsu.colorado.edu/~bethard/py/decorators-output.py http://ucsu.colorado.edu/~bethard/py/decorators-output.py
Decorator Location Decorator Location
------------------ ------------------
The first syntax point is the location of the decorators. For the The first syntax point is the location of the decorators. For the
following examples, we use the @syntax used in 2.4a2. following examples, we use the @syntax used in 2.4a2.
Decorators before the def statement are the first alternative, Decorators before the def statement are the first alternative,
@ -244,14 +245,14 @@ and the syntax used in 2.4a2::
def bar(low,high): def bar(low,high):
pass pass
There have been a number of objections raised to this location - There have been a number of objections raised to this location --
the primary one is that it's the first real Python case where a the primary one is that it's the first real Python case where a
line of code has a result on a following line. The syntax that line of code has a result on a following line. The syntax that
will be in 2.4a3 will also require one decorator per line (in a2, will be in 2.4a3 will also require one decorator per line (in a2,
multiple decorators can be specified on the same line). multiple decorators can be specified on the same line).
Some of the advantages of this form are that the decorators live Some of the advantages of this form are that the decorators live
outside the method body - they are obviously executed at the time outside the method body -- they are obviously executed at the time
the function is defined the function is defined
The second form is the decorators between the def and the function The second form is the decorators between the def and the function
@ -269,11 +270,11 @@ name, or the function name and the argument list::
def bar @accepts(int,int),@returns(float) (low,high): def bar @accepts(int,int),@returns(float) (low,high):
pass pass
There are a couple of objections to this form. There are a couple of objections to this form. The first is that it
The first is that it breaks easily 'greppability' of the source - you breaks easily 'greppability' of the source -- you can no longer search
can no longer search for 'def foo(' and find the definition of the for 'def foo(' and find the definition of the function. The second,
function. The second, more serious, objection is that in the case more serious, objection is that in the case of multiple decorators,
of multiple decorators, the syntax would be extremely unwieldy. the syntax would be extremely unwieldy.
The next form, which has had a number of strong proponents, is to The next form, which has had a number of strong proponents, is to
have the decorators between the argument list and the trailing ``:`` have the decorators between the argument list and the trailing ``:``
@ -297,7 +298,7 @@ also apply to the previous form) as:
- it's cumbersome to cut and paste a decorator list for reuse, because - it's cumbersome to cut and paste a decorator list for reuse, because
it starts and ends in the middle of a line it starts and ends in the middle of a line
.. summarised the arguments: .. _summarised the arguments:
http://mail.python.org/pipermail/python-dev/2004-August/047112.html http://mail.python.org/pipermail/python-dev/2004-August/047112.html
The next form is that the decorator syntax go inside the method The next form is that the decorator syntax go inside the method
@ -313,16 +314,16 @@ live:
@returns(float) @returns(float)
pass pass
The primary objection to this form is that it requires "peeking inside" The primary objection to this form is that it requires "peeking
the method body to determine the decorators. In addition, even though inside" the method body to determine the decorators. In addition,
the code is inside the method body, it is not executed when the method even though the code is inside the method body, it is not executed
is run. Guido felt that docstrings were not a good counter-example, and when the method is run. Guido felt that docstrings were not a good
that it was quite possible that a 'docstring' decorator could help move counter-example, and that it was quite possible that a 'docstring'
the docstring to outside the function body. decorator could help move the docstring to outside the function body.
The final form is a new block that encloses the method's code. For this The final form is a new block that encloses the method's code. For
example, we'll use a 'decorate' keyword, as it makes no sense with the this example, we'll use a 'decorate' keyword, as it makes no sense
@syntax. with the @syntax. ::
decorate: decorate:
classmethod classmethod
@ -336,47 +337,46 @@ example, we'll use a 'decorate' keyword, as it makes no sense with the
pass pass
This form would result in inconsistent indentation for decorated and This form would result in inconsistent indentation for decorated and
undecorated methods. In addition, a decorated method's body would start undecorated methods. In addition, a decorated method's body would
three indent levels in. start three indent levels in.
Syntax forms Syntax forms
------------ ------------
@decorator * ``@decorator``
The major objections against this syntax are that the @ symbol The major objections against this syntax are that the @ symbol is
is not currently used in Python (and is used in both IPython and not currently used in Python (and is used in both IPython and Leo),
Leo), that the @ symbol is not meaningful, that the @ symbol is not meaningful,
|decorator * ``|decorator``
This is a variant on the @decorator syntax - it has the advantage This is a variant on the @decorator syntax -- it has the advantage
that it does not break IPython and Leo. It's major disadvantage that it does not break IPython and Leo. Its major disadvantage
compared to the @syntax is that the | symbol looks like both a compared to the @syntax is that the | symbol looks like both a
capital I and a lowercase l. capital I and a lowercase l.
* list syntax * list syntax
The major objection to the list syntax is that it's currently The major objection to the list syntax is that it's currently
meaningful (when used in the form before the method). It's also meaningful (when used in the form before the method). It's also
lacking any indication that the expression is a decorator. lacking any indication that the expression is a decorator.
* list syntax using other brackets ( <...>, [[...]], ... ) * list syntax using other brackets (``<...>``, ``[[...]]``, ...)
* ``decorate()``
* decorate() The ``decorate()`` proposal was that no new syntax be implemented --
instead a magic function that used introspection to manipulate the
The decorate() proposal was that no new syntax be implemented - following function. Both Jp Calderone and Philip Eby produced
instead a magic function that used introspection to manipulate implementations of functions that did this. Guido was pretty firmly
the following function. Both Jp Calderone and Philip Eby produced against this -- with no new syntax, the magicness of a function like
implementations of functions that did this. Guido was pretty firmly this is extremely high.
against this - with no new syntax, the magicness of a function like
this is extremely high.
* new keyword (and block) * new keyword (and block)
Alternate Proposals Alternate Proposals
=================== ===================
@ -392,33 +392,24 @@ Several other syntaxes have been proposed::
The absence of brackets makes it cumbersome to break long lists of The absence of brackets makes it cumbersome to break long lists of
decorators across multiple lines, and the keyword "as" doesn't have decorators across multiple lines, and the keyword "as" doesn't have
the same meaning as its use in the ``import`` statement. Plenty of the same meaning as its use in the ``import`` statement. Plenty of
`alternatives to "as"`_ have been proposed. :-) `alternatives to "as"`_ have been proposed. :-) ::
.. _alternatives to "as":
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=mailman.236.1079968472.742.python-list%40python.org&rnum=2&prev=/groups%3Fq%3Dpython%2Bpep%2B318%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3Dmailman.236.1079968472.742.python-list%2540python.org%26rnum%3D2
::
def [dec1, dec2, ...] func(arg1, arg2, ...): def [dec1, dec2, ...] func(arg1, arg2, ...):
pass pass
This form has the disadvantage that the decorators visually assume .. _alternatives to "as":
higher priority than the function name and argument list. http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=mailman.236.1079968472.742.python-list%40python.org&rnum=2&prev=/groups%3Fq%3Dpython%2Bpep%2B318%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3Dmailman.236.1079968472.742.python-list%2540python.org%26rnum%3D2
:: This form has the disadvantage that the decorators visually assume
higher priority than the function name and argument list. ::
def func [dec1, dec2, ...] (arg1, arg2, ...): def func [dec1, dec2, ...] (arg1, arg2, ...):
pass pass
Quixote's `Python Template Language`_ uses this form, but only supports a Quixote's `Python Template Language`_ uses this form, but only
single decorator chosen from a restricted set. For short lists it supports a single decorator chosen from a restricted set. For short
works okay, but for long list it separates the argument list from the lists it works okay, but for long list it separates the argument list
function name. from the function name. ::
.. _Python Template Language:
http://www.mems-exchange.org/software/quixote/doc/PTL.html
::
using: using:
dec1 dec1
@ -427,6 +418,9 @@ function name.
def foo(arg1, arg2, ...): def foo(arg1, arg2, ...):
pass pass
.. _Python Template Language:
http://www.mems-exchange.org/software/quixote/doc/PTL.html
The function definition is not nested within the using: block making The function definition is not nested within the using: block making
it impossible to tell which objects following the block will be it impossible to tell which objects following the block will be
decorated. Nesting the function definition within the using: block decorated. Nesting the function definition within the using: block
@ -434,9 +428,7 @@ suggests nesting of namespaces that doesn't exist. The name ``foo``
would actually exist at the same scope as the using: block. Finally, would actually exist at the same scope as the using: block. Finally,
it would require the introduction of a new keyword. it would require the introduction of a new keyword.
The obvious alternative that nests the function within the block The obvious alternative that nests the function within the block ::
::
using: using:
dec1 dec1
@ -459,9 +451,10 @@ a `list of decorators`_ as a prefix to function definitions ::
def foo(arg1, arg2, ...): def foo(arg1, arg2, ...):
pass pass
For a while this was Guido's preferred solution, but negative sentiment ran For a while this was Guido's preferred solution, but negative
high, mostly because that syntax, though useless except for side sentiment ran high, mostly because that syntax, though useless except
effects of the list, is already legal and thus creates a special case. for side effects of the list, is already legal and thus creates a
special case.
.. _list of decorators: .. _list of decorators:
http://python.org/sf/926860 http://python.org/sf/926860
@ -481,7 +474,7 @@ that the decorators would be 'hidden'
Phillip Eby and Jp Calderone both proposed variants that required Phillip Eby and Jp Calderone both proposed variants that required
no new syntax, but instead used some fairly advanced introspection no new syntax, but instead used some fairly advanced introspection
to provide decorator-like behavoiur, but Guido was unimpressed by to provide decorator-like behavoiur, but Guido was unimpressed by
these, stating:: these, stating:
Using functions with "action-at-a-distance" through Using functions with "action-at-a-distance" through
sys.settraceback may be okay for an obscure feature that can't be sys.settraceback may be okay for an obscure feature that can't be
@ -501,17 +494,16 @@ incorporate its content into this PEP (hint, hint).
http://www.python.org/moin/PythonDecorators http://www.python.org/moin/PythonDecorators
Why @? Why @?
------ ------
There is some history in Java using @ initially as a marker in There is some history in Java using @ initially as a marker in
`Javadoc comments`_ and later in Java 1.5 for `annotations`_, `Javadoc comments`_ and later in Java 1.5 for `annotations`_, which
which are similar to Python decorators. The fact that are similar to Python decorators. The fact that @ was previously
@ was previously unused as a token in Python also means it's clear unused as a token in Python also means it's clear there is no
there is no possibility of such code being parsed by an earlier possibility of such code being parsed by an earlier version of Python,
version of Python, leading to possibly subtle semantic bugs. That leading to possibly subtle semantic bugs. That said, @ is still a
said, @ is still a fairly arbitrary choice. Some have suggested using fairly arbitrary choice. Some have suggested using | instead.
| instead.
For syntax options which use a list-like syntax (no matter where it For syntax options which use a list-like syntax (no matter where it
appears) to specify the decorators a few alternatives were proposed: appears) to specify the decorators a few alternatives were proposed:
@ -525,24 +517,23 @@ greater than symbol instead of a closer for the decorators.
.. _Javadoc comments: .. _Javadoc comments:
http://java.sun.com/j2se/javadoc/writingdoccomments/ http://java.sun.com/j2se/javadoc/writingdoccomments/
.. _annotations:
.. annotations:
http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html
Current Implementation Current Implementation
====================== ======================
Guido asked for a voluteer to implement his preferred syntax, and Mark Guido asked for a voluteer to implement his preferred syntax, and Mark
Russell stepped up and posted a `patch`_ to SF. The syntax accepted Russell stepped up and posted a `patch`_ to SF. The syntax accepted
for 2.4a2 is:: for 2.4a2 is::
@dec2 @dec2
@dec1 @dec1
def func(arg1, arg2, ...): def func(arg1, arg2, ...):
pass pass
is equivalent to:: This is equivalent to::
def func(arg1, arg2, ...): def func(arg1, arg2, ...):
pass pass
@ -550,11 +541,10 @@ is equivalent to::
though without the intermediate creation of a variable named ``func``. though without the intermediate creation of a variable named ``func``.
.. _patch: http://www.python.org/sf/979728
A `previous patch`_ from Michael Hudson which implements the A `previous patch`_ from Michael Hudson which implements the
list-after-def syntax is also still kicking around. list-after-def syntax is also still kicking around.
.. _patch: http://www.python.org/sf/979728
.. _previous patch: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff .. _previous patch: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff
@ -568,9 +558,7 @@ capability is much more powerful than that. This section presents
some examples of use. some examples of use.
1. Define a function to be executed at exit. Note that the function 1. Define a function to be executed at exit. Note that the function
isn't actually "wrapped" in the usual sense. isn't actually "wrapped" in the usual sense. ::
::
def onexit(f): def onexit(f):
import atexit import atexit
@ -584,7 +572,6 @@ some examples of use.
2. Define a class with a singleton instance. Note that once the class 2. Define a class with a singleton instance. Note that once the class
disappears enterprising programmers would have to be more creative disappears enterprising programmers would have to be more creative
to create more instances. (From Shane Hathaway on ``python-dev``.) to create more instances. (From Shane Hathaway on ``python-dev``.)
:: ::
def singleton(cls): def singleton(cls):
@ -600,9 +587,7 @@ some examples of use.
... ...
3. Add attributes to a function. (Based on an example posted by 3. Add attributes to a function. (Based on an example posted by
Anders Munch on ``python-dev``.) Anders Munch on ``python-dev``.) ::
::
def attrs(**kwds): def attrs(**kwds):
def decorate(f): def decorate(f):
@ -618,9 +603,7 @@ some examples of use.
4. Enforce function argument and return types. (Note that this is not 4. Enforce function argument and return types. (Note that this is not
exactly correct, as the returned new_f doesn't have "func" as its exactly correct, as the returned new_f doesn't have "func" as its
func_name attribute.) func_name attribute.) ::
::
def accepts(*types): def accepts(*types):
def check_accepts(f): def check_accepts(f):
@ -650,11 +633,7 @@ some examples of use.
5. Declare that a class implements a particular (set of) interface(s). 5. Declare that a class implements a particular (set of) interface(s).
This is from a posting by Bob Ippolito on ``python-dev`` based on This is from a posting by Bob Ippolito on ``python-dev`` based on
experience with `PyProtocols`_. experience with `PyProtocols`_. ::
.. _PyProtocols: http://peak.telecommunity.com/PyProtocols.html
::
def provides(*interfaces): def provides(*interfaces):
""" """
@ -674,6 +653,8 @@ some examples of use.
class Foo(object): class Foo(object):
"""Implement something here...""" """Implement something here..."""
.. _PyProtocols: http://peak.telecommunity.com/PyProtocols.html
Of course, all these examples are possible today, though without Of course, all these examples are possible today, though without
syntactic support. syntactic support.
@ -684,7 +665,7 @@ Open Issues
1. It's not yet certain that class decorators will be incorporated 1. It's not yet certain that class decorators will be incorporated
into the language at this point. Guido expressed skepticism about into the language at this point. Guido expressed skepticism about
the concept, but various people have made some `strong arguments`_ the concept, but various people have made some `strong arguments`_
(search for ``PEP 318 - posting draft``) on their behalf in (search for ``PEP 318 -- posting draft``) on their behalf in
``python-dev``. ``python-dev``.
.. _strong arguments: .. _strong arguments: