Python Decorators

For my Masters project I need a method by which the user can specify which functions should be run on an SPE1. This method should be simple, clear and easy to turn on and off. I stumbled upon a blog post a little while ago (I think it was this one) which explained decorators in Python, which is the perfect tool for the job. Decorators are used to transform functions, but without changing the function itself or the calls to it.

def spe(func, *args):
    def run(*args):
        return compile(func, *args)
    return run

@spe
def sub(a, b):
    return a - b

print sub(2, 4)

The spe function is the actual decorator. The @spe line applies the decorator to the sub function. Implicitly, the following declaration is made:

sub = spe(sub)

The sub function is being wrapped by the spe function, and so all calls to sub (such as the print line) will use the wrapped function instead. The decorator creates and returns a new function called run which will (eventually) cause the original function to be compiled and executed on an SPE. This means that running a function on an SPE will be as simple as adding @spe before the function declaration2, without having to change the way in which the function is called. Turning it off is as simple as commenting out this line, and it is fairly clear as to what is happening.


  1. Trying to make this decision automatically would be a massive project in itself and would probably be worse than a human decision. 

  2. There will probably be some restrictions on what the function may contain, but that's a different matter. 

Trackback URL for this post:

http://michael.gorven.za.net/trackback/30

I think your decorator

I think your decorator function def isn't doing quite what you expect.

Firstly, you don't need the *args in the definition for spe() unless you actually want to pass args to the decorator.

Secondly, you are changing the function to return whatever compile() returns, rather than what the function returns. If compile() calls the function on an SPE, what you have is correct. If compile() returns a compiled version that will run on an SPE, you probably want something like the following:

def spe(func):
    return compile(func)

Decorators are an exercise in higher-order functions, which aren't intuitive to someone with a background only in imperative programming. Learning some Lisp or Haskell is probably worth it if you want to wrap your head around this stuff properly. :-)

I am still wrapping my head

I am still wrapping my head around this, so forgive my fumbling. I haven't implemented this yet, but was intending for compile() to actually execute the function (in which case it's a bad name). The reason is that it will probably have to compile different versions for different types of parameters, and so this cannot be done once when the function is declared. Thanks for the tip about *args. :-)