python-peps / pep-3129.txt

PEP: 3129
Title: Class Decorators
Version: $Revision$
Last-Modified: $Date$
Author: Collin Winter <collinwinter@google.com>
Status: Final
Type: Standards Track
Content-Type: text/x-rst
Created: 1-May-2007
Python-Version: 3.0
Post-History: 7-May-2007


Abstract
========

This PEP proposes class decorators, an extension to the function
and method decorators introduced in PEP 318.


Rationale
=========

When function decorators were originally debated for inclusion in
Python 2.4, class decorators were seen as obscure and unnecessary
[#obscure]_ thanks to metaclasses.  After several years' experience
with the Python 2.4.x series of releases and an increasing
familiarity with function decorators and their uses, the BDFL and
the community re-evaluated class decorators and recommended their
inclusion in Python 3.0 [#approval]_.

The motivating use-case was to make certain constructs more easily
expressed and less reliant on implementation details of the CPython
interpreter.  While it is possible to express class decorator-like
functionality using metaclasses, the results are generally
unpleasant and the implementation highly fragile [#motivation]_.  In
addition, metaclasses are inherited, whereas class decorators are not,
making metaclasses unsuitable for some, single class-specific uses of
class decorators. The fact that large-scale Python projects like Zope
were going through these wild contortions to achieve something like
class decorators won over the BDFL.


Semantics
=========

The semantics and design goals of class decorators are the same as
for function decorators ([#semantics]_, [#goals]_); the only
difference is that you're decorating a class instead of a function.
The following two snippets are semantically identical::

  class A:
    pass
  A = foo(bar(A))
  
  
  @foo
  @bar
  class A:
    pass
    
For a detailed examination of decorators, please refer to PEP 318.


Implementation
==============

Adapting Python's grammar to support class decorators requires
modifying two rules and adding a new rule::

 funcdef: [decorators] 'def' NAME parameters ['->' test] ':' suite
 
 compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt |
                with_stmt | funcdef | classdef
                
need to be changed to ::
 
 decorated: decorators (classdef | funcdef)

 funcdef: 'def' NAME parameters ['->' test] ':' suite
 
 compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt |
                with_stmt | funcdef | classdef | decorated

Adding ``decorated`` is necessary to avoid an ambiguity in the
grammar.

The Python AST and bytecode must be modified accordingly.

A reference implementation [#implementation]_ has been provided by
Jack Diederich.


Acceptance
==========

There was virtually no discussion following the posting of this PEP,
meaning that everyone agreed it should be accepted.

The patch was committed to Subversion as revision 55430.


References
==========

.. [#obscure]
   http://www.python.org/dev/peps/pep-0318/#motivation
   
.. [#approval]
   http://mail.python.org/pipermail/python-dev/2006-March/062942.html
   
.. [#motivation]
   http://mail.python.org/pipermail/python-dev/2006-March/062888.html
   
.. [#semantics]
   http://www.python.org/dev/peps/pep-0318/#current-syntax

.. [#goals]
   http://www.python.org/dev/peps/pep-0318/#design-goals
   
.. [#implementation]
   http://python.org/sf/1671208
   


Copyright
=========

This document has been placed in the public domain.



..
   Local Variables:
   mode: indented-text
   indent-tabs-mode: nil
   sentence-end-double-space: t
   fill-column: 70
   coding: utf-8
   End:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.