Daily Archives: February 14, 2012

Python Decorators Featured

Intro to Python Decorators

Python Decorators Featured

Python decorators are one of the trickier but useful sides of the language, however I feel like they are often overlooked, so much so that, for example, I didn’t even know what they were until recently. As a result of writing a decorator that would automatically generate a routing URL tuple for web.py, I thought it would be nice to concentrate all the forum questions and blog posts that I used into a short introduction to the Python decorator scheme, not only to help myself understand them better, but possibly pass some information off to others as well.


For some inexplicable reason, I haven’t been able to pull myself way from the web.py framework. I’ve looked into the others out there, and have a small list of ones that I would like to do a serious project with at least once, however these projects are always on the back burner.

However there is one part of web.py that I don’t really like, and yet I do like. The URL routing tuple.

Sure it’s easy to use and understand, but really? I don’t want to have to maintain a list of URL’s to route to, and which object name they go with, I want to have the code automate this, so that all I do is tell it to generate an entry for an object, that will be at URL blank. So how do you do this? I have always preferred the flask/bottle way of doing routing, with decorators.

Simply put, I want to be able to simply do:

class singleFileObject(baseHTTPObject):

So my journey for the next few hours was set: learn enough about decorators to program a basic one that would do this for me.


Most regular Python guys should be able to pick this up in a heart beat:

def h1(f):
    return ("<h1>" + f() + "")

def f():
    return "hello, World!"

g = h1(f())

This is a basic decorator. It simply takes a function f as input, and returns that functions output wrapped in

tags. This is equivalent to doing:

def f():
    return "hello, World!"

So this begs to question: what can I do with one of these?

Back to Basics

Lets start with the basics. What is a decorator?

They’re in simple terms, a function or object which you “wrap” around another function or object. This allows you to modify the wrapped object on run time, or to modify the incoming arguments to the object.

And… what can you do with them?

Well, for starters, they allow you to do something before a function is called, or afterwards, or you can use them to make sure that a function always gets a specific type of arguments. There really is a near infinite things you can do with a decorator. For my personal use, I learned about decorators to write my own automatic router for my API’s that use web.py. Decorators are also really popular with tool programmers, however I have not seen them quiet as much in application programming. Another common use of decorators, is announcing a function or object to an API so that it may take advantage of the object. This is similar to what my goal is.

Okay, so now lets build this up from the ground to get a feel for how to use and program decorators.

The shortcut syntax for decorators in python is:

def f():
#which is equal to:
f = decorator(f())

From this you can build just about anything your heart desires. You can also chain together decorators:

def f():

#which unfolds to:
f = decoratorOne(decoratorTwo(f()))

But we’ll get to that later. First, lets look at what the decorator function looks like:

def decorator(targetObject):
    return targetObject()

def f():

Lines one and two are the decorator function. What it’s doing is simply intercepting the function f it is decorating on line 4 and then promptly returning it, with no operations or modifications done upon the function. Next up we’ll work with decorators which will intercept and print out the arguments passed to the function being decorated.

Advancing Forward

Now that we’ve looked at the basic decorator building blocks, lets look at a decorator that provides a little more usefulness.

Lets say we’re passing arguments to the function we want to decorate. We’ll write a basic decorator that prints out what arguments are passed, and passes those on to the function. This could allow us to produce a basic logging decorator, or to modify the arguments before they reach the function.

To do this we need to add a second function within the decorator which accepts *args and **kwargs, like so:

def decorator(targetObject):
    def argumentWrapper(*args, **kwargs):
        print "I got args: "
        print args
        print "And kwargs:"
        print kwargs
        targetObject(*args, **kwargs)
    return argumentWrapper

This will go through and intercept all the arguments, both none keyword’ed and keyword’ed arguments and print them out, followed by passing them to the target object or function we have decorated. So now we have a function structure that looks a little like so:

decorated function
    |----> functions arguments

Okay, cool. Now we can intercept arguments passed to a decorated function, then possibly modify them in some way, and modify the function itself, whats next?

Arguing with the Decorator

So now that we can decorate a function, and we have been able to pass arguments to that decorated function, lets look at passing arguments to the decorator itself. As it turns out, this is fairly logical in how its done, however not immediately obvious to some. The decorator function must first catch it’s arguments before it can catch the function being decorated, and that functions arguments, so we end up with a structure that looks a bit like this:

decorator arguments
    |----> function or object being decorated
        |----> decorated objects arguments

So now we can write a decorator function that looks like:

def decorator(*args, **kwargs):
    def wrapper(targetObject):
        def targetArguments(*args, **kwargs):
            targetObject(*args, **kwargs)
        return targetArguments
    return wrapper

Okay, neat trick Josh, but now what? We want to see a live example.

Alright, well I have one right here for you:

def wrapInTag(tag):
    print "Wrapping in a %s tag" % tag
    def targetToWrap(targetObject):
        def targetToWrapArguments(whatToSay):
            print "Saying: %s" % whatToSay
            return ("<%s>" % tag) + targetObject(whatToSay) + ("<!--%s-->" % tag)
        return targetToWrapArguments
    return targetToWrap

def saySomething(whatToSay):
    return whatToSay

>>> saySomething("Hello") #run the command
Saying: Hello
'<h1>Hello</h1>' #final result

Here we have a decorator called ‘wrapInTag’ which takes one argument, named tag as defined by line 1. This decorator then takes in a function whose output it will wrap in the given tag, and finally it allows the decorated function to take an input about what to say, and prints it all out in wrapped form when done.

Solution to Beginning Problem

My final solution for the web.py URL tuple problem was to pass a routing regex to the decorator, and use it to decorate the object that I wanted to map that regex match to:

urls = (
    "", "slash"

def route(routeURL):
    Router decorator
    Auto adds the decorated object to the url routing pool
        @route(regex pattern)
    def wrapper(HTTPObject):
        global urls
        urls += (routeURL, HTTPObject.__name__,)
        return HTTPObject
    return wrapper

class singleObject(baseHTTPObject):
    def get(self, **kwargs):
        return json.dumps({"message": "hello"})

Where to From Here?

Well, decorators are pretty powerful. I wrote one that, in 7 lines, generated and appended to the URL tuple in web.py a URL routing regex and which object to route that regex match to, so that I don’t have to manually enter objects into a URL tuple. I’ve seen decorators used for timing functions, logging or debugging. Their true power comes in the fact that they allow you to do such things as debug or log, or time without repeating code, and without changing the code within the decorated object. This is useful when your working with a library object and can not reprogram it, or the solution or code is only temporary.

Works Consulted

Web forums, articles and books used to help write this (and help me understand decorators).