Decorating recursive functions in python

If decorators indicate a prologue/epilogue to be done one before or after another function, we can avoid doing it several times simulating decorators with recursive functions.

For example:

def timing(f):
    def wrapper(*args):
       t1 = time.clock();
       r = apply(f,args)
       t2 = time.clock();
       print"%f seconds" % (t2-t1)
       return r
    return wrapper

@timing
def fibonacci(n):
    if n==1 or n==2:
      return 1
    return fibonacci(n-1)+fibonacci(n-2)

r = fibonacci(5)
print "Fibonacci of %d is %d" % (5,r)

Produces:

0.000000 seconds
0.000001 seconds
0.000026 seconds
0.000001 seconds
0.000030 seconds
0.000000 seconds
0.000001 seconds
0.000007 seconds
0.000045 seconds
Fibonacci of 5 is 5

We can simulate the decorator to force only one prologue/epilogue as:

r = timing(fibonacci)(5)
print "Fibonacci %d of is %d" % (5,r)

Which produces:

0.000010 seconds
Fibonacci 5 of is 5

All assignment in Python is just binding names to objects. When you have

f = dec(f)

what you are doing is binding the name f to the return value of dec(f). At that point, f no longer refers to the original function. The original function still exists and is called by the new f, but you don't have a named reference to the original function anymore.


As you said, the first one is called as usual.

the second one puts a decorated version of f called dec_f in the global scope. Dec_f is called, so that prints "Decorated!", but inside the f function passed to dec, you call f itself, not dec_f. the name f is looked up and found in the global scope, where it is still defined without the wrapper, so from than on, only f gets called.

in the 3re example, you assign the decorated version to the name f, so when inside the function f, the name f is looked up, it looks in the global scope, finds f, which is now the decorated version.