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.