views:

3122

answers:

13

While I like to think of myself as a reasonably competent Python coder, one aspect of the language I've never been able to grok is decorators.

I know what they are (superficially), I've read tutorials, examples, questions on Stack Overflow, and I understand the syntax, can write my own, occasionally use @classmethod and @staticmethod, but it never occurs to me to use a decorator to solve a problem in my own Python code. I never encounter a problem where I think, "Hmm...this looks like a job for a decorator!"

So, I'm wondering if you guys might offer some examples of where you've used decorators in your own programs, and hopefully I'll have an "A-ha!" moment and get them.

Edit - lots of good answers guys, thanks! I accepted David Makcenzie's because Bruce Eckel's article kind of clicked for me.

+4  A: 

I use them mainly for debugging (wrapper around a function that prints its arguments and result) and verification (e.g. to check if an argument is of correct type or, in the case of web application, if the user has sufficient privileges to call a particular method).

DzinX
+15  A: 

Decorators are used for anything that you want to transparently "wrap" with additional functionality.

Django uses them for wrapping "login required" functionality on view functions, as well as for registering filter functions.

You can use class decorators for adding named logs to classes.

Any sufficiently generic functionality that you can "tack on" to an existing class or function's behavior is fair game for decoration.

There's also a discussion of use cases on the Python-Dev newsgroup pointed to by PEP 318 -- Decorators for Functions and Methods.

cdleary
+12  A: 

The Twisted library uses decorators combined with generators to give the illusion that an asynchronous function is synchronous. For example:

@inlineCallbacks
def asyncf():
    doStuff()
    yield someAsynchronousCall()
    doStuff()
    yield someAsynchronousCall()
    doStuff()

Using this, code that would have been broken up into a ton of little callback functions can be written quite naturally as a single block, making it a lot easier to understand and maintain.

DNS
+4  A: 

I've actually recently had one of those "A-ha!" moments, as you call them, and used a decorator to enable me to profile decorated functions/methods only. It's the profile_func decorator in this file, the output of which can be viewed in KCacheGrind. Very useful indeed.

Walter
+4  A: 

Decorators are used either to define a function's properties or as boilerplate that alters it; it's possible but counter-intuitive for them to return completely different functions. Looking at the other responses here, it seems like one of the most common uses is to limit the scope of some other process - be it logging, profiling, security checks, etc.

CherryPy uses object-dispatching to match URLs to objects and, eventually, methods. Decorators on those methods signal whether or not CherryPy is even allowed to use those methods. For example, adapted from the tutorial:

class HelloWorld:

    ...

    def secret(self):
        return "You shouldn't be here."

    @cherrypy.expose
    def index(self):
        return "Hello world!"

cherrypy.quickstart(HelloWorld())
Nikhil Chelliah
This is not true. A decorator can completely change the behavior of a function.
recursive
Okay. But how often does a decorator "completely change the behavior of a function?" From what I've seen, when they're not used to specify properties, they're just used for boilerplate code.I've edited my response.
Nikhil Chelliah
+12  A: 

I use decorators for type checking parameters which are passed to my Python methods via some RMI. So instead of repeating the same parameter counting, exception-raising mumbo-jumbo again and again

def myMethod(ID, name):
    if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
        raise BlaBlaException() ...

I just declare

@accepts(uint, utf8string)
def myMethod(ID, name):
    ...

and accepts() does all the work for me.

Simon
For anyone interested, there's an implementation of `@accepts` in PEP 318.
martineau
+5  A: 

For nosetests, you can write a decorator that supplies a unit test function or method with several sets of parameters:

@parameters(
   (2, 4, 6),
   (5, 6, 11),
)
def test_add(a, b, expected):
    assert a + b == expected
Torsten Marek
+17  A: 

I've used them for synchronization.

def synchronized(lock):
    """ Synchronization decorator. """

    def wrap(f):
        def newFunction(*args, **kw):
            lock.acquire()
            try:
                return f(*args, **kw)
            finally:
                lock.release()
        return newFunction
    return wrap

You then use it like this:

import threading
lock = threading.Lock()

@synchronized(lock)
def do_something():
  # etc

@synchronzied(lock)
def do_something_else():
  # etc

Basically it just puts lock.acquire() / lock.release() on either side of the function call.

John Fouhy
+18  A: 

I use decorators mainly for timing purposes

def time_dec(func):

  def wrapper(*arg):
      t = time.clock()
      res = func(*arg)
      print func.func_name, time.clock()-t
      return res

  return wrapper


@time_dec
def myFunction(n):
    ...
RSabet
+12  A: 

Here is very good tutorial with good examples

Bruce Eckel on Decorators

Example : A Decorator-Based Build System

I found the article very useful.

TheMachineCharmer
+5  A: 

Recently, While working on social networking web application. For Community/Groups, i was suppose to give membership authorization to create new discussion and reply to a message you have to be the member of that particular group. So, I wrote a decorator @membership_required and put that where i required in my view. Python decorators are really powerful. It depends on your requirement.

aatifh
+4  A: 

There are a number of suggested usages and snippets at the Python wiki.

Paul McGuire
+3  A: 

I am using the following decorator for making a function threadsafe. It makes the code more readable. It is almost similar to the one proposed by John Fouhy but the difference is that one work on a single function and that there is no need to create a lock object explicitely.

def threadsafe_function(fn):
    """decorator making sure that the decorated function is thread safe"""
    lock = threading.Lock()
    def new(*args, **kwargs):
        lock.acquire()
        try:
            r = fn(*args, **kwargs)
        except Exception as e:
            raise e
        finally:
            lock.release()
        return r
    return new

class X:
    var = 0

    @threadsafe_function     
    def inc_var(self):
        X.var += 1    
        return X.var
luc
Does this mean each function, so decorated, has its own lock?
grieve
@grieve yes, every time the decorator is used (called) it creates a new lock object for the function/method being decorated.
martineau