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
=====================
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
an open-slather of plusses and minuses for each syntax, but is instead
to justify the choice made. If, in 2.4a3, the syntax is changed, the
PEP will be updated to match this, complete with the arguments for the
change.
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 an open-slather of plusses and minuses for each syntax, but is
instead to justify the choice made. If, in 2.4a3, the syntax is
changed, the PEP will be updated to match this, complete with the
arguments for the change.
Abstract
========
The current method for transforming functions and methods (for instance,
declaring them as a class or static method) is awkward and can lead to
code that is difficult to understand. Ideally, these transformations
should be made at the same point in the code where the declaration
itself is made. This PEP introduces new syntax for transformations of a
function or method declaration.
The current method for transforming functions and methods (for
instance, declaring them as a class or static method) is awkward and
can lead to code that is difficult to understand. Ideally, these
transformations should be made at the same point in the code where the
declaration itself is made. This PEP introduces new syntax for
transformations of a function or method declaration.
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
metaclasses, but using metaclasses is sufficiently obscure that there
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.
@ -104,87 +105,84 @@ Class decorations seem like an obvious next step because class
definition and function definition are syntactically similar.
The discussion continued on and off on python-dev from February 2002
through July 2004. Hundreds and hundreds of posts were made, with people
proposing many possible syntax variations. Guido took a list 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`_
@decorator syntax. Barry Warsaw named this the 'pie-decorator'
syntax, in honor of the Pie-thon Parrot shootout which was announced
about the same time as the decorator syntax, and because the @ looks a
little like a pie. Guido `outlined his case`_ on Python-dev,
including `this piece`_ on the various rejected forms.
through July 2004. Hundreds and hundreds of posts were made, with
people proposing many possible syntax variations. Guido took a list
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`_ @decorator syntax. Barry Warsaw named this the
'pie-decorator' syntax, in honor of the Pie-thon Parrot shootout which
was announced about the same time as the decorator syntax, and because
the @ looks a little like a pie. Guido `outlined his case`_ on
Python-dev, including `this piece`_ on the various rejected forms.
.. _EuroPython 2004:
http://www.python.org/doc/essays/ppt/euro2004/euro2004.pdf
.. _outlined his case:
http://mail.python.org/pipermail/python-dev/2004-August/author.html
.. _this piece:
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
On the name 'Decorator'
=======================
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
not consistent with it's use in the `GoF book`_. The name 'decorator'
probably owes more to it's use in the compiler area - a syntax tree
is walked and annotated. It's quite possible that a better name may
turn up.
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 not
consistent with its use in the `GoF book`_. The name 'decorator'
probably owes more to its use in the compiler area -- a syntax tree is
walked and annotated. It's quite possible that a better name may turn
up.
.. GoF book:
.. _GoF book:
http://patterndigest.com/patterns/Decorator.html
Design Goals
============
The new syntax should
* work for arbitrary wrappers, including user-defined callables and
the existing builtins ``classmethod()`` and ``staticmethod()``
* work for arbitrary wrappers, including user-defined callables and
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
obvious that new users can safely ignore it when writing their own
code
* 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
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
frequently
* be easy to type; programs that use it are expected to use it very
frequently
* not make it more difficult to scan through code quickly. It should
still be easy to search for all definitions, a particular
definition, or the arguments that a function accepts
* not make it more difficult to scan through code quickly. It should
still be easy to search for all definitions, a particular
definition, or the arguments that a function accepts
* not needlessly complicate secondary support tools such as
language-sensitive editors and other "`toy parser tools out
there`_"
* not needlessly complicate secondary support tools such as
language-sensitive editors and other "`toy parser tools out
there`_"
* move from the end of the function, where it's currently hidden, to
the front where it is more `in your face`_
* move from the end of the function, where it's currently hidden, to
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:
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
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:
http://www.amk.ca/diary/archives/cat_python.html#003255
.. _Jim Huginin's list of use cases:
http://mail.python.org/pipermail/python-dev/2004-April/044132.html
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
clear that something new is going on here.
The decorator statement is limited in what it can accept - arbitrary
expressions will not work. Guido preferred this because of a `gut feeling`_
The decorator statement is limited in what it can accept -- arbitrary
expressions will not work. Guido preferred this because of a `gut
feeling`_.
.. _gut feeling:
http://mail.python.org/pipermail/python-dev/2004-August/046711.html
Syntax Alternatives
===================
There have been `a large number`_ of different syntaxes proposed - rather
than attempting to work through these individual syntaxes, it's worthwhile
to break the syntax discussion down into a number of areas. Attempting to
discuss `each possible syntax`_ individually would be an act of madness,
and produce a completely unwieldly PEP.
There have been `a large number`_ of different syntaxes proposed --
rather than attempting to work through these individual syntaxes, it's
worthwhile to break the syntax discussion down into a number of areas.
Attempting to discuss `each possible syntax`_ individually would be an
act of madness, and produce a completely unwieldly PEP.
.. a large number:
.. _a large number:
http://www.python.org/moin/PythonDecorators
.. each possible syntax:
.. _each possible syntax:
http://ucsu.colorado.edu/~bethard/py/decorators-output.py
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.
Decorators before the def statement are the first alternative,
@ -244,14 +245,14 @@ and the syntax used in 2.4a2::
def bar(low,high):
pass
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
line of code has a result on a following line. The syntax that
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
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,
multiple decorators can be specified on the same line).
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 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):
pass
There are a couple of objections to this form.
The first is that it breaks easily 'greppability' of the source - you
can no longer search for 'def foo(' and find the definition of the
function. The second, more serious, objection is that in the case
of multiple decorators, the syntax would be extremely unwieldy.
There are a couple of objections to this form. The first is that it
breaks easily 'greppability' of the source -- you can no longer search
for 'def foo(' and find the definition of the function. The second,
more serious, objection is that in the case of multiple decorators,
the syntax would be extremely unwieldy.
The next form, which has had a number of strong proponents, is to
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 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
The next form is that the decorator syntax go inside the method
@ -313,16 +314,16 @@ live:
@returns(float)
pass
The primary objection to this form is that it requires "peeking inside"
the method body to determine the decorators. In addition, even though
the code is inside the method body, it is not executed when the method
is run. Guido felt that docstrings were not a good counter-example, and
that it was quite possible that a 'docstring' decorator could help move
the docstring to outside the function body.
The primary objection to this form is that it requires "peeking
inside" the method body to determine the decorators. In addition,
even though the code is inside the method body, it is not executed
when the method is run. Guido felt that docstrings were not a good
counter-example, and that it was quite possible that a 'docstring'
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
example, we'll use a 'decorate' keyword, as it makes no sense with the
@syntax.
The final form is a new block that encloses the method's code. For
this example, we'll use a 'decorate' keyword, as it makes no sense
with the @syntax. ::
decorate:
classmethod
@ -336,47 +337,46 @@ example, we'll use a 'decorate' keyword, as it makes no sense with the
pass
This form would result in inconsistent indentation for decorated and
undecorated methods. In addition, a decorated method's body would start
three indent levels in.
undecorated methods. In addition, a decorated method's body would
start three indent levels in.
Syntax forms
------------
@decorator
* ``@decorator``
The major objections against this syntax are that the @ symbol
is not currently used in Python (and is used in both IPython and
Leo), that the @ symbol is not meaningful,
The major objections against this syntax are that the @ symbol is
not currently used in Python (and is used in both IPython and Leo),
that the @ symbol is not meaningful,
|decorator
* ``|decorator``
This is a variant on the @decorator syntax - it has the advantage
that it does not break IPython and Leo. It's major disadvantage
compared to the @syntax is that the | symbol looks like both a
capital I and a lowercase l.
This is a variant on the @decorator syntax -- it has the advantage
that it does not break IPython and Leo. Its major disadvantage
compared to the @syntax is that the | symbol looks like both a
capital I and a lowercase l.
* list syntax
The major objection to the list syntax is that it's currently
meaningful (when used in the form before the method). It's also
lacking any indication that the expression is a decorator.
The major objection to the list syntax is that it's currently
meaningful (when used in the form before the method). It's also
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 following function. Both Jp Calderone and Philip Eby produced
implementations of functions that did this. Guido was pretty firmly
against this - with no new syntax, the magicness of a function like
this is extremely high.
The ``decorate()`` proposal was that no new syntax be implemented --
instead a magic function that used introspection to manipulate the
following function. Both Jp Calderone and Philip Eby produced
implementations of functions that did this. Guido was pretty firmly
against this -- with no new syntax, the magicness of a function like
this is extremely high.
* new keyword (and block)
Alternate Proposals
===================
@ -392,33 +392,24 @@ Several other syntaxes have been proposed::
The absence of brackets makes it cumbersome to break long lists of
decorators across multiple lines, and the keyword "as" doesn't have
the same meaning as its use in the ``import`` statement. Plenty of
`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
::
`alternatives to "as"`_ have been proposed. :-) ::
def [dec1, dec2, ...] func(arg1, arg2, ...):
pass
This form has the disadvantage that the decorators visually assume
higher priority than the function name and argument list.
.. _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
::
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, ...):
pass
Quixote's `Python Template Language`_ uses this form, but only supports a
single decorator chosen from a restricted set. For short lists it
works okay, but for long list it separates the argument list from the
function name.
.. _Python Template Language:
http://www.mems-exchange.org/software/quixote/doc/PTL.html
::
Quixote's `Python Template Language`_ uses this form, but only
supports a single decorator chosen from a restricted set. For short
lists it works okay, but for long list it separates the argument list
from the function name. ::
using:
dec1
@ -427,6 +418,9 @@ function name.
def foo(arg1, arg2, ...):
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
it impossible to tell which objects following the block will be
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,
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:
dec1
@ -459,9 +451,10 @@ a `list of decorators`_ as a prefix to function definitions ::
def foo(arg1, arg2, ...):
pass
For a while this was Guido's preferred solution, but negative sentiment ran
high, mostly because that syntax, though useless except for side
effects of the list, is already legal and thus creates a special case.
For a while this was Guido's preferred solution, but negative
sentiment ran high, mostly because that syntax, though useless except
for side effects of the list, is already legal and thus creates a
special case.
.. _list of decorators:
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
no new syntax, but instead used some fairly advanced introspection
to provide decorator-like behavoiur, but Guido was unimpressed by
these, stating::
these, stating:
Using functions with "action-at-a-distance" through
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
Why @?
Why @?
------
There is some history in Java using @ initially as a marker in
`Javadoc comments`_ and later in Java 1.5 for `annotations`_,
which are similar to Python decorators. The fact that
@ was previously unused as a token in Python also means it's clear
there is no possibility of such code being parsed by an earlier
version of Python, leading to possibly subtle semantic bugs. That
said, @ is still a fairly arbitrary choice. Some have suggested using
| instead.
`Javadoc comments`_ and later in Java 1.5 for `annotations`_, which
are similar to Python decorators. The fact that @ was previously
unused as a token in Python also means it's clear there is no
possibility of such code being parsed by an earlier version of Python,
leading to possibly subtle semantic bugs. That said, @ is still a
fairly arbitrary choice. Some have suggested using | instead.
For syntax options which use a list-like syntax (no matter where it
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:
http://java.sun.com/j2se/javadoc/writingdoccomments/
.. annotations:
.. _annotations:
http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html
Current Implementation
======================
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::
@dec2
@dec1
def func(arg1, arg2, ...):
pass
is equivalent to::
This is equivalent to::
def func(arg1, arg2, ...):
pass
@ -550,11 +541,10 @@ is equivalent to::
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
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
@ -568,9 +558,7 @@ capability is much more powerful than that. This section presents
some examples of use.
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):
import atexit
@ -584,7 +572,6 @@ some examples of use.
2. Define a class with a singleton instance. Note that once the class
disappears enterprising programmers would have to be more creative
to create more instances. (From Shane Hathaway on ``python-dev``.)
::
def singleton(cls):
@ -600,9 +587,7 @@ some examples of use.
...
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 decorate(f):
@ -618,9 +603,7 @@ some examples of use.
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
func_name attribute.)
::
func_name attribute.) ::
def accepts(*types):
def check_accepts(f):
@ -650,11 +633,7 @@ some examples of use.
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
experience with `PyProtocols`_.
.. _PyProtocols: http://peak.telecommunity.com/PyProtocols.html
::
experience with `PyProtocols`_. ::
def provides(*interfaces):
"""
@ -674,6 +653,8 @@ some examples of use.
class Foo(object):
"""Implement something here..."""
.. _PyProtocols: http://peak.telecommunity.com/PyProtocols.html
Of course, all these examples are possible today, though without
syntactic support.
@ -684,7 +665,7 @@ Open Issues
1. It's not yet certain that class decorators will be incorporated
into the language at this point. Guido expressed skepticism about
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``.
.. _strong arguments: