Python Decorators as Closures

Python decorators are a feature of the language that allows the programmer to alter the behavior of a function or class at runtime and without having to use techniques such as subclassing.

For example, let’s assume I need to trace the code path over several functions. This is easily accomplished with a decorator:

def myTrace(f):
    def trace_func():
        print "Entered", f.__name__
        f()
        print "Exiting", f.__name__
    return trace_func

@myTrace
def function1():
    print "Inside Function1"
    function2()

@myTrace
def function2():
    print "Inside Function2"

function1()

The output of this script is:

Entered function1
Inside Function1
Entered function2
Inside Function2
Exiting function2
Exiting function1

Decorators in Python allow me to do more than just simple text substitution (C macros). Decorators effectively replaced one function for another in the example above. I can prove that there is actual substitution by adding the statement print function1.__name__ to the end of the above script. What is the current name of function1?

The more interesting thing that decorators allow me to do is to close over the parent scope of the decorator. Let’s look a this example:

def helloWorld(f):
    s = "World!"

    def new_func():
        print f(), s

    return new_func

@helloWorld
def func():
    return "Hello"

func()

The output of the script above is Hello World!, but the only call is to func() and that function does not print anything. This is because I substitute func() for the new_func() definition that I created inside the decorator. The new definition is, for all intents and purposes, a closure, because it encapsulates the context of the decorator and of func().

I can prove this theory: comment out the @helloWorld decorator before the func() definition and run the script again. What is the output now?

Comments

Comments powered by Disqus