Differences between revisions 30 and 31
Revision 30 as of 2004-08-06 14:15:39
Size: 8221
Editor: JimJJewett
Comment:
Revision 31 as of 2004-08-06 14:24:33
Size: 9106
Editor: JimJJewett
Comment:
Deletions are marked like this. Additions are marked like this.
Line 88: Line 88:
'''C. list-after-def syntax''' '''C1. list-after-def syntax'''
Line 116: Line 116:
'''C2. list-after-def syntax with a (pseudo-)keyword'''
{{{
def foo(arg1,arg2) using [classmethod]:
    ...

def bar(low,high) using [accepts(int,int), returns(float)]:
    ...
}}}

This combines C1 with a keyword; it general, it has all the advantages
of either, so I will only list those that are unique to the combination.

 * + Groups the decorators with a list, but explains what they are
doing, so the list no longer has a magical new meaning.
 * + Easily extended; No special characters are "used up", and in
the future, other pseudo-keywords could be added.
 * - Some proponents objected to adding a keyword, because of more
typing.
 * 0 Makes the decoration look like a second-class or optional part of
the definition. This is true, but may have caused some emotional
objection.
 * - There was very little agreement on which word should be used.

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

C1. 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.

C2. list-after-def syntax with a (pseudo-)keyword

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

def bar(low,high) using [accepts(int,int), returns(float)]:
    ...

This combines C1 with a keyword; it general, it has all the advantages of either, so I will only list those that are unique to the combination.

  • + Groups the decorators with a list, but explains what they are

doing, so the list no longer has a magical new meaning.

  • + Easily extended; No special characters are "used up", and in

the future, other pseudo-keywords could be added.

  • - Some proponents objected to adding a keyword, because of more

typing.

  • 0 Makes the decoration look like a second-class or optional part of

the definition. This is true, but may have caused some emotional objection.

  • - There was very little agreement on which word should be used.

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.