Update of /cvsroot/python/python/nondist/peps
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2332
Modified Files:
pep-0318.txt
Log Message:
Checking in what we have so far. Still digesting some of Jim Jewett's
inputs.
Index: pep-0318.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0318.txt,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** pep-0318.txt 28 Feb 2004 19:09:44 -0000 1.4
--- pep-0318.txt 23 Mar 2004 16:41:17 -0000 1.5
***************
*** 3,243 ****
Version: $Revision$
Last-Modified: $Date$
! Author: Kevin D. Smith <Kevin.Smith at theMorgue.org>
Status: Draft
Type: Standards Track
! Content-Type: text/plain
Created: 05-Jun-2003
Python-Version: 2.4
! Post-History: 09-Jun-2003, 10-Jun-2003, 27-Feb-2004
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. Using the latter form, the last example above
! would look like:
! def foo(self) as (synchronized(lock), classmethod):
! perform method operation
! This form make is possible for the list of decorators to
! span multiple lines without using the line continuation operator.
! Alternate Syntaxes
! Other syntaxes have been proposed in comp.lang.python and
! python-dev. Unfortunately, no one syntax has come out as a clear
! winner in the lengthy discussions. The most common suggestions
! are demonstrated below. The proposed syntax is also included
! for easy comparison.
! Proposed Syntax
! def foo(self) as synchronized(lock), classmethod:
! perform method operation
! def foo(self) as (synchronized(lock), classmethod):
! perform method operation
! Prefix Forms
! def [synchronized(lock), classmethod] foo(self):
! perform method operation
! def synchronized(lock), classmethod foo(self):
! perform method operation
! # Same as above, but only identifiers are allowed
! sync = synchronized(lock)
! def sync, classmethod foo(self):
! perform method operation
! # Java-like
! sync = synchronized(lock)
! def @sync @classmethod foo(self):
! perform method operation
! Postfix Forms
! 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
! I'm not as fond of the forms that use '[ ]' since code like
! 'foo()[a]' looks as if you are getting the item 'a' from 'foo()'.
! Although, this isn't as much of an issue when using '[ ]' in
! a prefix form. The Java-like syntax adds new syntax that is
! very arbitrary and is almost Perl-ish. In addition, since the
! order in which the decorators are applied may matter, the last,
! 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 executed. 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 when the 'def' statement is executed.
! Open Issues
! It is not clear at the moment if it is even possible to have
! multiple decorators for a function. If decorators are required
! to take a function/method and return a descriptor, it might
! not even be possible to wrap multiple decorators. This should
! be explored since the best syntax for multiple decorators
! may not be the same as the best syntax for a single decorator.
! Current Implementations
! I am not personally familiar enough with Python's source to
! implement the proposed syntax; however, Michael Hudson has
! implemented the "square-bracketed" syntax (see patch at
! http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar.diff).
! It should be fairly simple for the Python development team
! to translate this patch to the proposed syntax.
! 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.
--- 3,281 ----
Version: $Revision$
Last-Modified: $Date$
! Author: Kevin D. Smith <Kevin.Smith at theMorgue.org>,
! Jim Jewett <jimjjewett at users.sourceforge.net>,
! Skip Montanaro <skip at pobox.com>
Status: Draft
Type: Standards Track
! Content-Type: text/x-rst
Created: 05-Jun-2003
Python-Version: 2.4
! 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
! transformations of a declaration.
Motivation
+ ==========
! The current method of applying a transformation to a function or
! method places the actual translation after the function body. For
! large functions this separates a key component of the function's
! behavior from the definition of the rest of the function's external
! interface. For example::
! def foo(self):
! perform method operation
! foo = classmethod(foo)
! This becomes less readable with longer methods. It also seems less
! than pythonic to name the function three times for what is
! conceptually a single declaration. A solution to this problem is to
! move the transformation of the method closer to the method's own
! declaration. While the new syntax is not yet final, the intent is to
! replace::
! def foo(cls):
! pass
! foo = synchronized(lock)(foo)
! foo = classmethod(foo)
+ with an alternative that places the decoration in the function's
+ declaration::
! def foo(cls) using [synchronized(lock), classmethod]:
! pass
! Background
! ==========
! There is general agreement that syntactic support is desirable to the
! current state of affairs. Guido mentioned `syntactic support for
! decorators`_ in his DevDay keynote presentation at the `10th Python
! 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`_.
! .. _syntactic support for decorators: http://www.python.org/doc/essays/ppt/python10/py10keynote.pdf
! .. _10th python conference: http://www.python.org/workshops/2002-02/
! .. _michael hudson raised the topic: http://mail.python.org/pipermail/python-dev/2002-February/020005.html
! .. _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
! Design Goals
! ============
! The new syntax should
! * work for arbitrary wrappers, including user-defined callables and
! the existing builtins ``classmethod()`` and ``staticmethod``
! * 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
! * not make future extensions more difficult
! * 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 needlessly complicate secondary support tools such as
! language-sensitive editors and other "`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
! Proposed Syntax
! ===============
! The currently proposed syntax is::
! def func(arg1, arg2, ...) [dec1, dec2, ...]:
! pass
! 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.
! Alternate Proposals
! ===================
! A few other syntaxes have been proposed::
! def func(arg1, arg2, ...) as dec1, dec2, ...:
! 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.
! ::
! def [dec1, dec2, ...] func(arg1, arg2, ...):
! pass
! This form has the disadvantage that the decorators become visually
! 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
! 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
! dec2
! ...
! def foo(arg1, arg2, ...):
! pass
! 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.
! Current Implementation
! ======================
! Michael Hudson has posted a `patch`_ at Starship, which implements the
! proposed syntax and left-first application of decorators::
! def func(arg1, arg2, ...) [dec1, dec2]:
! pass
! is equivalent to::
! def func(arg1, arg2, ...):
! pass
! func = dec2(dec1(func))
! though without the intermediate creation of a variable named ``func``.
! .. _patch: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar.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.
! 1. Define a function to be executed at exit. Note that the function
! isn't actually "wrapped" in the usual sense.
! ::
! def onexit(f):
! import atexit
! atexit.register(f)
! return f
+ def func() [onexit]:
+ ...
! 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):
! return cls()
! class MyClass [singleton]:
! ...
+ 3. Decorate a function with release information. (Based on an example
+ posted by Anders Munch on ``python-dev``.)
! ::
! def release(**kwds):
! def decorate(f):
! for k in kwds:
! setattr(f, k, kwds[k])
! return f
! return decorate
! def classmethod(f) [release(versionadded="2.2",
! author="Guido van Rossum")]:
! ...
! 4. Enforce function argument and return types.
!
! ::
!
! def accepts(*types):
! def check_accepts(f):
! 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
!
! def returns(rtype):
! def check_returns(f):
! def new_f(*args, **kwds):
! result = f(*args, **kwds)
! assert isinstance(result, rtype), \
! "return value %r does not match %s" % (result,rtype)
! return result
! return new_f
! return check_returns
!
! def func(arg1, arg2) [accepts(int, (int,float)),
! returns((int,float))]:
! return arg1 * arg2
!
! Of course, all these examples are possible today, though without the
! syntactic support.
!
! Possible Extensions
! ===================
!
! The proposed syntax is general enough that it could be used on class
! definitions as well::
!
! class foo(object) [dec1, dec2, ...]:
! class definition here
!
! Use would likely be much less than function decorators. The current
! patch only implements function decorators.
Copyright
+ =========
! This document has been placed in the public domain.