Python decorators


Patrick Boucher recently posted a SetValue decorator for Softimage that can temporarily change any value for the duration of a method call and restore it afterward.

So, what’s a decorator?
After glancing at the SetValue decorator code and taking a quick look at the docs at python.org, I needed a simple example to help me wrap my head around the syntax (which turned it to be simpler than what I was expecting).

So, here’s a simple example of a decorator.
func_timer is the decorator function, and all it does is time how long a function takes.

import time

# Define the decorator function
def func_timer(func):
	def wrapper(*arg):
		t = time.clock()
		res = func(*arg)
		print func.func_name, time.clock()-t
		return res
	return wrapper

# Wrap myFunction with the decorator
@func_timer
def myFunction(n):
	for i in range(n):
		Application.CreatePrim("Cube", "MeshSurface", "", "")

# Call myFunction
myFunction(3)


# Do the equivalent, but without using a decorator:
def myFunction1(n):
	for i in range(n):
		Application.CreatePrim("Cube", "MeshSurface", "", "")

myFunction1 = func_timer( myFunction1 )(40)

I found this Python Decorators Don’t Have to be (that) Scary article helpful.

And from the python.org glossary, I learned that:

a decorator is “merely synatic sugar” that is a “function returning another function, usually applied as a function transformation using the @wrapper syntax.”

From the Python language reference, I learned that:

A function definition may be wrapped by one or more decorator expressions. Decorator expressions are evaluated when the function is defined, in the scope that contains the function definition. The result must be a callable, which is invoked with the function object as the only argument. The returned value is bound to the function name instead of the function object. Multiple decorators are applied in nested fashion. For example, the following code:

@f1(arg)
@f2
def func(): pass

is equivalent to:

def func(): pass
func = f1(arg)(f2(func))

By the next day, it all made sense 😉