Sunday, June 5, 2011

Python Decorator with Optional Keyword Arguments


Decorators in Python are extremely useful tools. This syntactic sugar is an integral part of standard python code, and can be custom-built to make your own code more succinct and awesome.

I've used decorators to mark functions as deprecated, make them curryable, make sure a user is authenticated (when that method was a render method in a Twisted resource), and more. Recently I was using them to add a little bit of magic to a collection of methods that I needed to use a lot, that had a lot of repeated code in them. I needed to sometimes set up the executing environment of those functions a little differently than usual though, using keyword options that I would pass to the decorator. I've seen decorators used this way before, so I figured it would be easy. Uhm, not so much.
Decorators are a little confusing to people who haven't written them before. The idea is simple:
@decorator
def function():
    pass
 
def function():
    pass
function = decorator(function)
A decorator is basically just a function (it can also be done with a class) which takes a function as its argument, and returns a function. The decorator in the example above might have been:
def decorator(func):
    def inner(*args, **kwargs):
        print "This is a decorated function!"
        func(*args, **kwargs)
    return inner
 
@decorator
def function(x):
    print x
 
function(42)
#> This is a decorated function!
#> 42
The decorator takes a function. It creates a new, "inner" function and closes the passed function. In the inner function, we print something, then call the original function. You can see this in action in this example, where calling the decorated function results in the text "This is a decorated function!" being printed.
A decorator can also take arguments: