Differences between revisions 29 and 30
Revision 29 as of 2004-08-06 12:24:16
Size: 7751
Editor: gate
Comment:
Revision 30 as of 2004-08-06 14:15:39
Size: 8221
Editor: JimJJewett
Comment:
Deletions are marked like this. Additions are marked like this.
Line 65: Line 65:
 * 0 The @ character is often used (in other languages) to mean "attribute". For annotations, this is good. For more active decorators, it may not be so good.
Line 103: Line 104:
 * - Guido didn't like (maybe because of line wrap issue?)  * - Guido didn't like (maybe because of line wrap issue?)
 * - Creates another meaning for []. Since it does so inside the function definition, it will be a distraction for beginners.
Line 146: Line 148:
 * Could use @doc to as a docstring alternative  * Could use @doc too as a docstring alternative
Line 192: Line 194:
 * - Most characters (including pipe) already have a meaning. Ending an expression at the linebreak will probably keep these from becoming ambiguous, but ... that gets fragile.

Support for decorators was proposed for Python in [http://www.python.org/peps/pep-0318.html PEP 318], and will be implemented in Python 2.4.

What is a decorator

A decorator is a software design pattern. Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.

For more information about the decorator pattern in general, see:

Debate about decorators in Python

The winning syntax as of now uses the '@' symbol, as described in [http://mail.python.org/pipermail/python-dev/2004-June/045516.html this message]. Mark Russell implemented this version. [http://mail.python.org/pipermail/patches/2004-July/015452.html Here] is the message describing the patch he checked in.

There has been a long discussion about the syntax to use for decorators in Python. See for example these threads:

Examples

   1 @classmethod
   2 def foo (arg1, arg2):
   3     ....

See also: MixIns, MetaClasses

Current Decorator Proposals

After the @decorator syntax was "accepted", lots of people threw up alarms and a huge series of threads started exploding on Python-dev. Here are the current alternatives that I could find that are being argued, with pros and cons:

I give two examples that might be common uses in the future. Classmethod declarations, and something like static typing (adapters), declaring what type parameters a function expects and returns.

A. pie decorator syntax

@classmethod
def foo(arg1,arg2):
    ...

@accepts(int,int)
@returns(float)
def bar(low,high):
    ...
  • + Java-like, so not completely unknown to everyone.
  • + Makes the syntax obvious visually
  • + Will not be silently ignored
  • + Compile-time
  • + Separate from the def syntax (desired by some for making decoration stand out and keeping def the same)
  • - Separate from the def syntax (undesired by some for simple decorators like classmethod/staticmethod)
  • - Ugly?
  • - The @ special character is used in IPython and Leo
  • - Punctuation-based syntax raises Perlfears.
  • - Because of no indentation, looks confusing when definitions are not separated by empty lines.
  • - Breaks in interactive shell
  • - Comes before the def keyword. Supercedes the function declaration itself.
  • 0 The @ character is often used (in other languages) to mean "attribute". For annotations, this is good. For more active decorators, it may not be so good.

B. list-before-def syntax

[classmethod]
def foo(arg1,arg2):
    ...

[accepts(int,int), returns(float)]
def bar(low,high):
    ...
  • + C# like
  • + Can be made backwards compatible-ish, with a "hack"
  • + Doesn't cause breakage in existing code-searching tools
  • - Doesn't cause breakage in existing code-searching tools
  • - Would not work in interactive mode (list would be interpreted right away)
  • - EuroPython didn't like it ( why? )

  • - The backwards compatability wouldn't be portable to Jython
  • - Looks like a normal expression, but has "magic" behavior of altering a function object
  • - Breaks in interactive shell

C. list-after-def syntax

def foo(arg1,arg2) [classmethod]:
    ...

def bar(low,high) [accepts(int,int), returns(float)]:
    ...
  • + Also somewhat C#-like
  • + Was a "community favorite" at one time
  • + Clearly a part of function declaration
  • + Looks ok for simple decorators such as classmethod
  • + Won't break simplistic code analyzers or grep for function def
  • - Long lists of decorators/arguments cause ugly line wraps
  • - Little to distinguish it visually from argument list
  • - or 0 For long argument list, decorators are very far from def. I see being too close to def as a minus.

  • - Guido didn't like (maybe because of line wrap issue?)
  • - Creates another meaning for []. Since it does so inside the function definition, it will be a distraction for beginners.

I don't see why longs lists of decorators are an issue with this syntax. Consider the following example:

def foo(arg1, arg2) [
    complicated(manyArgs=1, notTooUgly='yes'),
    even_more_complicated(42)]:
    ...

That doesn't look particularly ugly to me.

D. list at top of function body syntax

def foo(arg1,arg2):
    [classmethod]
    ...

def bar(low,high):
    [accepts(int,int), returns(float)]
    ...
  • + Also somewhat C#-like
  • + Consistent with how docstrings are used.
  • + Looks ok for simple or complex decorators
  • + Won't break simplistic code analyzers or grep for function def
  • + Solves line wrap problem with above proposal
  • 0 There is a hack that implements this now [http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/286147 here].

  • - Guido's europython presentation said this didn't win out, but not why
  • - Adds 'magic' behavior to a normal python expression (lists).
  • 0 Perhaps decorators should be allowed before or after the docstring. If you have to choose, I'd choose making it before the docstring.

E. pie decorator at top of function body syntax

def foo(arg1,arg2):
    @classmethod
    ...

def bar(low,high):
    @accepts(int,int)
    @returns(float)
    ...
  • Same as above but with pie syntax.
  • Could use @doc too as a docstring alternative

F. inline syntax

def classmethod foo(arg1,arg2):
    ...

?
  • + Simple
  • + Obviousely attached to the function
  • - Does not allow for arguments to the decorator inline, or multiple decorators
  • - The natural place where everyone looks for the function name now is a possible container for other information
  • - Complicates things like colorization and other functions of helper tools

G. as decorator

as classmethod
def foo(arg1,arg2):
    ...

?
  • + Non-punctuation based
  • + Does not use an existing mechanism with 'magic' behavior
  • - Guido specifically vetos: "as" means "rename" in too many logical, common places that are

H. pie decorator using a different character

For example, using the '|' character:

|classmethod
def foo(arg1,arg2):
    ...

|accepts(int,int)
|returns(float)
def bar(low,high):
    ...

Same pros and cons as @decorator, but additionally:

  • + It doesn't break Leo, IPython, or any other tool that uses @ as a special character.
  • + The association with pipes makes some sense: "take this thing and pass it through that thing to get a modified thing".
  • - Most characters (including pipe) already have a meaning. Ending an expression at the linebreak will probably keep these from becoming ambiguous, but ... that gets fragile.

Thinking ahead to Python 3 ?

[http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&safe=off&selm=Pine.LNX.4.44.0408050856390.31290-100000%40ccc9.wpi.edu&rnum=1 Christopher King] makes the point that we are trying to do too much with decorators: declare class/static methods, describe function metadata, and mangle functions. It might be best to think about what is best for each separately.

How might fully loaded functions look in the future?

Christopher King's example:

def classmethod foo(self,a,b,c):
    """Returns a+b*c."""
    {accepts: (int,int,int), author: 'Chris King'}

    return a+b*c

Another possible example (keyword support for staticmethod & classmethod, visual basic-like typing using the "as" keyword for adapters, "with" code blocks):

def classmethod foo(a as int, b as int, c as list) as list:
    """Returns a+b*c."""

    listcopy = []
    with synchronized(lock):
        listcopy[] = c[]

    return a+b*listcopy

Here it is with the @ symbol:

 @author('Chris King')
 @accepts(int,int,list)
 @classmethod
 def foo(self,a,b,c):
     """Returns a+b*c."""

      return a+b*c

PythonDecorators (last edited 2016-05-20 20:14:18 by FranciscoReyes)

Unable to edit the page? See the FrontPage for instructions.