Add verbiage about class decorators and their status
This commit is contained in:
parent
490a2e2fdd
commit
c83ec2f982
122
pep-0318.txt
122
pep-0318.txt
|
@ -1,5 +1,5 @@
|
|||
PEP: 318
|
||||
Title: Function/Method Decorator Syntax
|
||||
Title: Decorators for Functions, Methods and Classes
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Kevin D. Smith <Kevin.Smith@theMorgue.org>,
|
||||
|
@ -15,11 +15,11 @@ Post-History: 09-Jun-2003, 10-Jun-2003, 27-Feb-2004, 23-Mar-2004
|
|||
|
||||
Abstract
|
||||
========
|
||||
|
||||
The current method for declaring class and static methods 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
|
||||
|
||||
The current method for declaring class and static methods 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 declaration.
|
||||
|
||||
|
||||
|
@ -54,6 +54,13 @@ declaration::
|
|||
def foo(cls) using [synchronized(lock), classmethod]:
|
||||
pass
|
||||
|
||||
Modifying classes in this fashion is also possible, though the
|
||||
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.
|
||||
|
||||
Background
|
||||
==========
|
||||
|
||||
|
@ -64,8 +71,7 @@ Conference`_, though `he later said`_ it was only one of several
|
|||
extensions he proposed there "semi-jokingly". `Michael Hudson raised
|
||||
the topic`_ on ``python-dev`` shortly after the conference,
|
||||
attributing the bracketed syntax to an earlier proposal on
|
||||
``comp.lang.python`` by `Gareth
|
||||
McCaughan`_.
|
||||
``comp.lang.python`` by `Gareth McCaughan`_.
|
||||
|
||||
.. _syntactic support for decorators: http://www.python.org/doc/essays/ppt/python10/py10keynote.pdf
|
||||
.. _10th python conference: http://www.python.org/workshops/2002-02/
|
||||
|
@ -73,6 +79,9 @@ McCaughan`_.
|
|||
.. _he later said: http://mail.python.org/pipermail/python-dev/2002-February/020017.html
|
||||
.. _gareth mccaughan: http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=slrna40k88.2h9o.Gareth.McCaughan%40g.local
|
||||
|
||||
Class decorations seem like an obvious next step because class
|
||||
definition and function definition are syntactically similar.
|
||||
|
||||
Design Goals
|
||||
============
|
||||
|
||||
|
@ -83,17 +92,17 @@ The new syntax should
|
|||
|
||||
* 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
|
||||
* 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
|
||||
|
||||
* 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
|
||||
|
||||
* not make it more difficult to scan through code quickly. It should
|
||||
still be easy to search for all definitions, a particular
|
||||
* 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
|
||||
|
@ -105,7 +114,7 @@ The new syntax should
|
|||
Proposed Syntax
|
||||
===============
|
||||
|
||||
The currently proposed syntax is::
|
||||
The currently proposed syntax for function decorators is::
|
||||
|
||||
def func(arg1, arg2, ...) [dec1, dec2, ...]:
|
||||
pass
|
||||
|
@ -114,6 +123,11 @@ The decorators are near the declaration of the function's API but are
|
|||
clearly secondary. The square brackets make it possible to fairly
|
||||
easily break long lists of decorators across multiple lines.
|
||||
|
||||
Class decorators are defined in an analogous fashion::
|
||||
|
||||
class MyClass(base1, base2) [dec1, dec2, ...]:
|
||||
pass
|
||||
|
||||
Alternate Proposals
|
||||
===================
|
||||
|
||||
|
@ -123,15 +137,18 @@ A few other syntaxes have been proposed::
|
|||
pass
|
||||
|
||||
The absence of brackets makes it cumbersome to break long lists of
|
||||
decorators across multiple lines. The keyword "as" doesn't have the
|
||||
same meaning as its use in the ``import`` statement.
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
def [dec1, dec2, ...] func(arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
This form has the disadvantage that the decorators become visually
|
||||
This form has the disadvantage that the decorators visually assume
|
||||
higher priority than the function name and argument list.
|
||||
|
||||
::
|
||||
|
@ -139,11 +156,13 @@ higher priority than the function name and argument list.
|
|||
def func [dec1, dec2, ...] (arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
Quixote's Page Template Language uses this form, but only supports a
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
using:
|
||||
|
@ -156,15 +175,16 @@ function name.
|
|||
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
|
||||
suggests block structure 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.
|
||||
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.
|
||||
|
||||
Current Implementation
|
||||
======================
|
||||
|
||||
Michael Hudson has posted a `patch`_ at Starship, which implements the
|
||||
proposed syntax and left-first application of decorators::
|
||||
Michael Hudson posted a `patch`_ at Starship, which implements the
|
||||
proposed syntax changes for both functions and classes and left-first
|
||||
application of decorators::
|
||||
|
||||
def func(arg1, arg2, ...) [dec1, dec2]:
|
||||
pass
|
||||
|
@ -177,15 +197,16 @@ is equivalent to::
|
|||
|
||||
though without the intermediate creation of a variable named ``func``.
|
||||
|
||||
.. _patch: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar.diff
|
||||
.. _patch: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Much of the discussion on ``comp.lang.python`` and the ``python-dev``
|
||||
mailing list focuses on the use of the ``staticmethod()`` and
|
||||
``classmethod()`` builtins. This capability is much more powerful
|
||||
than that. This section presents some examples of use.
|
||||
mailing list focuses on the use of decorators as a cleaner way to use
|
||||
the ``staticmethod()`` and ``classmethod()`` builtins. This
|
||||
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.
|
||||
|
@ -224,8 +245,8 @@ than that. This section presents some examples of use.
|
|||
return f
|
||||
return decorate
|
||||
|
||||
def classmethod(f) [release(versionadded="2.2",
|
||||
author="Guido van Rossum")]:
|
||||
def mymethod(f) [release(versionadded="2.2",
|
||||
author="Guido van Rossum")]:
|
||||
...
|
||||
|
||||
4. Enforce function argument and return types.
|
||||
|
@ -234,12 +255,12 @@ than that. This section presents some examples of use.
|
|||
|
||||
def accepts(*types):
|
||||
def check_accepts(f):
|
||||
assert len(types) == f.func_code.co_argcount
|
||||
def new_f(*args, **kwds):
|
||||
for (a, t) in zip(args, types):
|
||||
assert isinstance(a, t), \
|
||||
"arg %r does not match %s" % (a,t)
|
||||
return f(*args, **kwds)
|
||||
assert len(types) == f.func_code.co_argcount
|
||||
return new_f
|
||||
return check_accepts
|
||||
|
||||
|
@ -257,20 +278,43 @@ than that. This section presents some examples of use.
|
|||
returns((int,float))]:
|
||||
return arg1 * arg2
|
||||
|
||||
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
|
||||
::
|
||||
|
||||
def provides(*interfaces):
|
||||
"""
|
||||
An actual, working, implementation of provides for
|
||||
the current implementation of PyProtocols. Not
|
||||
particularly important for the PEP text.
|
||||
"""
|
||||
def provides(typ):
|
||||
declareImplementation(typ, instancesProvide=interfaces)
|
||||
return typ
|
||||
return provides
|
||||
|
||||
class IBar(Interface):
|
||||
"""Declare something about IBar here"""
|
||||
|
||||
class Foo(object) [provides(IBar)]:
|
||||
"""Implement something here..."""
|
||||
|
||||
Of course, all these examples are possible today, though without the
|
||||
syntactic support.
|
||||
|
||||
Possible Extensions
|
||||
===================
|
||||
Open Issues
|
||||
===========
|
||||
|
||||
The proposed syntax is general enough that it could be used on class
|
||||
definitions as well::
|
||||
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
|
||||
``python-dev``.
|
||||
|
||||
class foo(object) [dec1, dec2, ...]:
|
||||
class definition here
|
||||
|
||||
Use would likely be much less than function decorators. The current
|
||||
patch only implements function decorators.
|
||||
.. _strong arguments: http://mail.python.org/pipermail/python-dev/2004-March/thread.html
|
||||
|
||||
|
||||
Copyright
|
||||
|
|
Loading…
Reference in New Issue