[Python-3000] Adding class decorators to PEP 318 (original) (raw)
Guido van Rossum guido at python.org
Tue May 1 19:19:21 CEST 2007
- Previous message: [Python-3000] Adding class decorators to PEP 318
- Next message: [Python-3000] Why isinstance() and issubclass() don't need to be unforgeable
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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: RevisionRevisionRevision Last-Modified: DateDateDate 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()andstaticmethod()) have been +Two method decorators (classmethod()andstaticmethod()) 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 revisitedin 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 theJava-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. Guidooutlined his caseon Python-dev, includingthis pieceon 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 theorder 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 decidedhe preferredhaving 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 Guidosummarized the argumentsagainst 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 + + + 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/)
- Previous message: [Python-3000] Adding class decorators to PEP 318
- Next message: [Python-3000] Why isinstance() and issubclass() don't need to be unforgeable
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]