[Python-3000] Adding class decorators to PEP 318

Guido van Rossum guido at python.org
Tue May 1 19:19:21 CEST 2007


I don't like this -- it seems like rewriting history to me. I'd rather
leave PEP 318 alone and create a new PEP. Of course the new PEP can be
short because it can refer to PEP 318.

--Guido

On 5/1/07, Collin Winter <collinw at gmail.com> wrote:
> In talking to Neal Norwitz about this, I don't see a need for a
> separate PEP for class decorators; we already have a decorators PEP,
> #318. The following is a proposed patch to PEP 318 that adds in class
> decorators.
>
> Collin Winter
>
>
> Index: pep-0318.txt
> ===================================================================
> --- pep-0318.txt        (revision 55034)
> +++ pep-0318.txt        (working copy)
> @@ -1,5 +1,5 @@
>  PEP: 318
> -Title: Decorators for Functions and Methods
> +Title: Decorators for Functions, Methods and Classes
>  Version: $Revision$
>  Last-Modified: $Date$
>  Author: Kevin D. Smith, Jim Jewett, Skip Montanaro, Anthony Baxter
> @@ -9,7 +9,7 @@
>  Created: 05-Jun-2003
>  Python-Version: 2.4
>  Post-History: 09-Jun-2003, 10-Jun-2003, 27-Feb-2004, 23-Mar-2004, 30-Aug-2004,
> -              2-Sep-2004
> +              2-Sep-2004, 30-Apr-2007
>
>
>  WarningWarningWarning
> @@ -22,24 +22,40 @@
>  negatives of each form.
>
>
> +UpdateUpdateUpdate
> +==================
> +
> +In April 2007, this PEP was updated to reflect the evolution of the Python
> +community's attitude toward class decorators.  Though they had previously
> +been rejected as too obscure and with limited use-cases, by mid-2006,
> +class decorators had come to be seen as the logical next step, with some
> +wondering why they hadn't been included originally.  As a result, class
> +decorators will ship in Python 2.6.
> +
> +This PEP has been modified accordingly, with references to class decorators
> +injected into the narrative.  While some references to the lack of class
> +decorators have been left in place to preserve the historical record, others
> +have been removed for the sake of coherence.
> +
> +
>  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, methods and classes (for
> +instance, declaring a method 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, method or class declaration.
>
>
>  Motivation
>  ==========
>
> -The current method of applying a transformation to a function or method
> -places the actual transformation 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
> +The current method of applying a transformation to a function, method or class
> +places the actual transformation after the body.  For large
> +code blocks this separates a key component of the object's behavior from
> +the definition of the rest of the object's external interface.  For
>  example::
>
>      def foo(self):
> @@ -69,14 +85,22 @@
>  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 decorators are being added.
> +to having an easier way to make simple modifications to classes.  The
> +following is much clearer than the metaclass-based alternative::
>
> +    @singleton
> +    class Foo(object):
> +        pass
>
> +Because of the greater ease-of-use of class decorators and the symmetry
> +with function and method decorators, class decorators will be included in
> +Python 2.6.
> +
> +
>  Why Is This So Hard?
>  --------------------
>
> -Two decorators (``classmethod()`` and ``staticmethod()``) have been
> +Two method decorators (``classmethod()`` and ``staticmethod()``) have been
>  available in Python since version 2.2.  It's been assumed since
>  approximately that time that some syntactic support for them would
>  eventually be added to the language.  Given this assumption, one might
> @@ -135,11 +159,16 @@
>  .. _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
> +Class decorations seemed like an obvious next step because class
>  definition and function definition are syntactically similar,
> -however Guido remains unconvinced, and class decorators will almost
> -certainly not be in Python 2.4.
> +however Guido was not convinced of their usefulness, and class
> +decorators were not in Python 2.4.  `The issue was revisited`_ in March 2006
> +and sufficient use-cases were found to justify the inclusion of class
> +decorators in Python 2.6.
>
> +.. _The issue was revisited:
> +   http://mail.python.org/pipermail/python-dev/2006-March/062942.html
> +
>  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
> @@ -147,8 +176,8 @@
>  place.  Subsequent to this, he decided that we'd have the `Java-style`_
>  @decorator syntax, and this appeared for the first time in 2.4a2.
>  Barry Warsaw named this the 'pie-decorator' syntax, in honor of the
> -Pie-thon Parrot shootout which was occured around the same time as
> -the decorator syntax, and because the @ looks a little like a pie.
> +Pie-thon Parrot shootout which was occuring around the same time as
> +the decorator syntax debate, and because the @ looks a little like a pie.
>  Guido `outlined his case`_ on Python-dev, including `this piece`_
>  on some of the (many) rejected forms.
>
> @@ -250,6 +279,19 @@
>  decorators are near the function declaration.  The @ sign makes it clear
>  that something new is going on here.
>
> +Python 2.6's class decorators work similarly::
> +
> +    @dec2
> +    @dec1
> +    class Foo:
> +        pass
> +
> +This is equivalent to::
> +
> +    class Foo:
> +        pass
> +    Foo = dec2(dec1(Foo))
> +
>  The rationale for the `order of application`_ (bottom to top) is that it
>  matches the usual order for function-application.  In mathematics,
>  composition of functions (g o f)(x) translates to g(f(x)).  In Python,
> @@ -321,7 +363,7 @@
>  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 an effect on a following line.  The syntax available in 2.4a3
> -requires one decorator per line (in a2, multiple decorators could be
> +requires one decorator per line (in 2.4a2, multiple decorators could be
>  specified on the same line).
>
>  People also complained that the syntax quickly got unwieldy when
> @@ -330,52 +372,61 @@
>  were small and thus this was not a large worry.
>
>  Some of the advantages of this form are that the decorators live outside
> -the method body -- they are obviously executed at the time the function
> +the function/class body -- they are obviously executed at the time the object
>  is defined.
>
> -Another advantage is that a prefix to the function definition fits
> +Another advantage is that a prefix to the definition fits
>  the idea of knowing about a change to the semantics of the code before
> -the code itself, thus you know how to interpret the code's semantics
> +the code itself. This way, you know how to interpret the code's semantics
>  properly without having to go back and change your initial perceptions
>  if the syntax did not come before the function definition.
>
>  Guido decided `he preferred`_ having the decorators on the line before
> -the 'def', because it was felt that a long argument list would mean that
> -the decorators would be 'hidden'
> +the 'def' or 'class', because it was felt that a long argument list would mean
> +that the decorators would be 'hidden'
>
>  .. _he preferred:
>      http://mail.python.org/pipermail/python-dev/2004-March/043756.html
>
> -The second form is the decorators between the def and the function name,
> -or the function name and the argument list::
> +The second form is the decorators between the 'def' or 'class' and the object's
> +name, or between the name and the argument list::
>
>      def @classmethod foo(arg1,arg2):
>          pass
> +
> +    class @singleton Foo(arg1, arg2):
> +        pass
>
>      def @accepts(int,int), at returns(float) bar(low,high):
>          pass
>
>      def foo @classmethod (arg1,arg2):
>          pass
> +
> +    class Foo @singleton (arg1, arg2):
> +        pass
>
>      def bar @accepts(int,int), at 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
> +breaks easy '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 ``:`` in the
> -'def' line::
> +'def' or 'class' line::
>
>      def foo(arg1,arg2) @classmethod:
>          pass
>
>      def bar(low,high) @accepts(int,int), at returns(float):
>          pass
> +
> +    class Foo(object) @singleton:
> +        pass
>
>  Guido `summarized the arguments`_ against this form (many of which also
>  apply to the previous form) as:
> @@ -403,15 +454,19 @@
>          @accepts(int,int)
>          @returns(float)
>          pass
> +
> +    class Foo(object):
> +        @singleton
> +        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
> +the suite body to determine the decorators.  In addition, even though
> +the code is inside the suite body, it is not executed when the code
>  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
> +The final form is a new block that encloses the function or clas.  For this
>  example, we'll use a 'decorate' keyword, as it makes no sense with the
>  @syntax. ::
>
> @@ -425,9 +480,14 @@
>          returns(float)
>          def bar(low,high):
>              pass
> +
> +    decorate:
> +        singleton
> +        class Foo(object):
> +            pass
>
>  This form would result in inconsistent indentation for decorated and
> -undecorated methods.  In addition, a decorated method's body would start
> +undecorated code.  In addition, a decorated object's body would start
>  three indent levels in.
>
>
> @@ -444,6 +504,10 @@
>      @returns(float)
>      def bar(low,high):
>          pass
> +
> +    @singleton
> +    class Foo(object):
> +        pass
>
>    The major objections against this syntax are that the @ symbol is
>    not currently used in Python (and is used in both IPython and Leo),
> @@ -461,6 +525,10 @@
>      |returns(float)
>      def bar(low,high):
>          pass
> +
> +    |singleton
> +    class Foo(object):
> +        pass
>
>    This is a variant on the @decorator syntax -- it has the advantage
>    that it does not break IPython and Leo.  Its major disadvantage
> @@ -476,6 +544,10 @@
>      [accepts(int,int), returns(float)]
>      def bar(low,high):
>          pass
> +
> +    [singleton]
> +    class Foo(object):
> +        pass
>
>    The major objection to the list syntax is that it's currently
>    meaningful (when used in the form before the method).  It's also
> @@ -490,6 +562,10 @@
>      <accepts(int,int), returns(float)>
>      def bar(low,high):
>          pass
> +
> +    <singleton>
> +    class Foo(object):
> +        pass
>
>    None of these alternatives gained much traction. The alternatives
>    which involve square brackets only serve to make it obvious that the
> @@ -659,7 +735,10 @@
>  .. _subsequently rejected:
>       http://mail.python.org/pipermail/python-dev/2004-September/048518.html
>
> +For Python 2.6, the Python grammar and compiler were modified to allow
> +class decorators in addition to function and method decorators.
>
> +
>  Community Consensus
>  -------------------
> _______________________________________________
> Python-3000 mailing list
> Python-3000 at python.org
> http://mail.python.org/mailman/listinfo/python-3000
> Unsubscribe: http://mail.python.org/mailman/options/python-3000/guido%40python.org
>


-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list