decorator with keyword

Peter Otten __peter__ at web.de
Thu Aug 12 05:17:15 EDT 2004


I'm sure they have been mentioned somewhere but here are some more
advantages of a decorator keyword (I use "transform"):

- The docstring can be moved to the top of the decorator suite.
- Simple attributes that don't affect the function's operation directly can
  be written in the "natural" name = value form.
- Though I expect them to be rare like they are in classes today, statements
  like if __debug__: decorateForDebugging would be possible.
          
A docstring and a single decorator - the common case:

transform:
    """  Factory for new decorator syntaxes.
         
         Keeps all proposals in a list and will recombine 
         them at random if called without a spec. """
   staticmethod
def makeDecoratorSyntax(spec=None):
    raise NotImplementedException()

The same with a pie:

@staticmethod
def makeDecoratorSyntax(spec=None):
    """  Factory for new decorator syntaxes.
         
         Keeps all proposals in a list and will recombine 
         them at random if called without a spec. """
    raise NotImplementedException()

I'd say no clear winner here. Now a heavily decorated function:

transform:
    """This method blah, blah.

    It supports the following arguments:
    - longArgumentOne -- a string giving ...
    - longArgumentTwo -- a number giving ...

    blah, blah.

    """
    author = "BDFL"
    status = "experimental"
    grammar = "'@' dotted_name [ '(' [arglist] ')' ]"
    staticmethod 
def longMethodNameForEffect(longArgumentOne=None,
                            longArgumentTwo=42):
    if longArgumentOne is None:
        longArgumentOne = setDefault(longArgumentTwo)
    for line in longArgumentOne:
        if not isBogus(line):
            print line

The same with pies:

@funcattrs(author="BDFL", status="experimental",
    grammar="'@' dotted_name [ '(' [arglist] ')' ]")
@staticmethod 
def longMethodNameForEffect(longArgumentOne=None,
                            longArgumentTwo=42):
    """This method blah, blah.

    It supports the following arguments:
    - longArgumentOne -- a string giving ...
    - longArgumentTwo -- a number giving ...

    blah, blah.

    """
    if longArgumentOne is None:
        longArgumentOne = setDefault(longArgumentTwo)
    for line in longArgumentOne:
        if not isBogus(line):
            print line

A long docstring can indeed tear apart signature and implementation.

For the sake of completeness, a plain old function:

def filter(cond, seq):
    """filter(function or None, sequence) -> list, tuple, or string

    Return those items of sequence for which function(item) is true.  If
    function is None, return the items that are true.  If sequence is a
    tuple or string, return the same type, else return a list."""

    if cond is None:
        cond = bool
    return [item for item in seq if cond(item)]

transform:
    """filter(function or None, sequence) -> list, tuple, or string

    Return those items of sequence for which function(item) is true.  If
    function is None, return the items that are true.  If sequence is a
    tuple or string, return the same type, else return a list."""
def filter(cond, seq):
    if cond is None:
        cond = bool
    return [item for item in seq if cond(item)]

"transform" looks a bit pathetic for a docstring, but otherwise I'd say the
grouping might even be slighly clearer. Note how the function signature is
duplicated in the docstring taken from 2.3's filter() - that helps a lot
for long decoration suites.

The decoration suite would generate a list of (name, value) tuples which are
applied to the function like so

trafos = [("__doc__", "This method..."), ("author", "BDFL"), ..., (None,
staticmethod)]
trafos.reverse()
for name, value in trafos:
    if name:
        setattr(func, name, value)
    else:
        func = value(func)

I think I would even prefer something like the above over the current
classdict passed to metaclasses, i. e. ordering information and "unnamed
attributes" could be useful in classes, too.

Peter




More information about the Python-list mailing list