Decorators

Steven D'Aprano steve at pearwood.info
Fri Mar 6 15:46:21 CET 2009


Johny wrote:

> Hi,
> Can anyone explain to me what are decorators for? What are advantages 
> of using them?

Decorators are for many things. One thing is for factoring out common
functionality. Suppose, for example, you have a number of functions that
all test that the argument is larger than zero. Here's two:

def spam(n):
    if n <= 0:
        raise ValueError("argument must be positive")
    return "spam "*n

def spammier(n):
    if n <= 0:
        raise ValueError("argument must be positive")
    return "spam spam wonderful SPAM "*n

Imagine you have lots of them. The common code is wasteful, tedious to type,
and it breaks the DRY principle ("Don't Repeat Yourself"). If you decide
that the functions need a different test, you have to change every single
function, which is prone to errors -- it's easy to miss one, or make a
mistake. So let's factor the common code out, using a decorator:

def test_argument(some_function):
    # Decorator that checks that the argument to some_function is > 0.
    def func(arg):
        # The code common to all functions.
        if n <= 0:
            raise ValueError("argument must be positive")
        # Now call the decorated function.
        return some_function(arg)
    return func

Notice that the decorator "test_argument" returns the function object "func"
itself, not the result of calling func().

Now let's see how to use it, first the old-fashioned way:

def spam(n):
    return "spam "*n

spam = test_argument(spam)


This is so common that Python uses special syntax to simplify it.

@test_argument
def spammier(n):
    return "spam spam wonderful SPAM "*n



Now if you need to change the test, say to ensure that n is at least five
instead of one, you can change it in a single place, inside the decorator.



-- 
Steven




More information about the Python-list mailing list