What are some common uses for Python decorators? [closed]

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.


Solution 1:

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):
    ...

Solution 2:

I've used them for synchronization.

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            lock.acquire()
            try:
                return f(*args, **kw)
            finally:
                lock.release()
        return newFunction
    return wrap

As pointed out in the comments, since Python 2.5 you can use a with statement in conjunction with a threading.Lock (or multiprocessing.Lock since version 2.6) object to simplify the decorator's implementation to just:

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            with lock:
                return f(*args, **kw)
        return newFunction
    return wrap

Regardless, 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.