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.