Decorators in Python

A few days ago, I mentioned that I was going to start coding Python again. So, I was looking at Python 2.5 and one of the cooler features that I discovered first were decorators. From what I understand, a decorator wraps behavior of a function or method. It sort of reminds me of auxiliary methods in Common Lisp. A Python function or method can be decorated.

So, I created I quick example that creates a decorator. The simplest decorator is a regular function that accepts a single argument, the function that is being decorated. The decorator returns another function that accepts an argument set and an environment. This is basically a lexical closure. In my decorator, logged, the inner function wrapper is enclosed and wrapper just prints out a message:

def logged(f):
  def wrapper(*args, **kw):
    print "calling %s with args %s." % (f.func_name, args)
    try:
      return f(*args, **kw)
    finally:
      print "done calling %s" % (f.func_name)
  return wrapper

The interesting thing is that wrapper ends up calling the function object passed into the decorator. In this case, the function object is the decorated function add():

@logged
def add(n1, n2):
  return n1 + n2
print add(2, 1)
print add(4, -2)

My simple adder is decorated by the @logged syntax. The Python runtime will execute the decorator and call the closure, passing the arguments from the original function call. When I execute my test program:

$ python decorate.py
calling add with args (2, 1).
done calling add
3
calling add with args (4, -2).
done calling add
2

Awesome! Now, there is more to decorators than meets the eye, and I need to gain more experience using decorators. So, it looks like I am off to a great start.



%d bloggers like this: