Python uses the decorator to optimize the example of tail recursion. python Recursion
Introduction to tail recursion
Tail recursion is the function that returns the last operation that is a recursive call, and the function is tail recursion.
Recursion is linear. For example, each call to the factorial function creates a new stack (last-in-first-out) and uses continuous stack pressure to create recursion, stack Overflow is easily caused. Tail recursion uses the current stack to optimize recursive functions through data coverage.
The factorial function factorial completes tail recursion by passing the calculated value. However, python does not require the compiler to optimize tail recursion. Therefore, an error will still be reported when recursion is performed multiple times ).
Eg:
def factorial(n, x): if n == 0: return x else: return factorial(n-1, n*x)print factorial(5, 1) # 120
Tail recursion Optimization
Here we use the Fibonacci number as an example. The linear recursive algorithm is passed out because it is too inefficient. Let's take a look at the call in the method of delivery at the end:
(n,b1=1,b2=1,c=3): if n<3: return 1 else: if n==c: return b1+b2 else: return Fib(n,b1=b2,b2=b1+b2,c=c+1)
To test this program, call Fib (1001:
>>> def Fib(n,b1=1,b2=1,c=3):... if n<3:... return 1... else:... if n==c:... return b1+b2... else:... return Fib(n,b1=b2,b2=b1+b2,c=c+1)... >>> Fib(1001)70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501L>>>
If we use Fib (1002), the result is as follows:
..... File "<stdin>", line 8, in Fib File "<stdin>", line 8, in Fib File "<stdin>", line 8, in Fib File "<stdin>", line 8, in Fib File "<stdin>", line 8, in Fib File "<stdin>", line 8, in FibRuntimeError: maximum recursion depth exceeded>>>
Now let's optimize the tail recursion.
Add a Decorator to the Fib function, as shown below:
@tail_call_optimizeddef Fib(n,b1=1,b2=1,c=3): if n<3: return 1 else: if n==c: return b1+b2 else: return Fib(n,b1=b2,b2=b1+b2,c=c+1)
Well, this is the decorator @ tail_call_optimized. This decorator makes Python magically break the call stack restrictions.
Even if we run Fib (20000), we can run the results in 2000 ms (MS is the result of the Yuan netbook mentioned in the previous blog)
Let's take a look at the Magic Code below:
class TailRecurseException: def __init__(self, args, kwargs): self.args = args self.kwargs = kwargs def tail_call_optimized(g): """ This function decorates a function with tail call optimization. It does this by throwing an exception if it is it's own grandparent, and catching such exceptions to fake the tail call optimization. This function fails if the decorated function recurses in a non-tail context. """ def func(*args, **kwargs): f = sys._getframe() if f.f_back and f.f_back.f_back and f.f_back.f_back.f_code == f.f_code: raise TailRecurseException(args, kwargs) else: while 1: try: return g(*args, **kwargs) except TailRecurseException, e: args = e.args kwargs = e.kwargs func.__doc__ = g.__doc__ return func
The methods used have been shown before. I am very impressed by the fact that the author throws an exception and captures it to break the growth of the Call Stack, which is simply incredible. In addition, the efficiency problem is about five times the time overhead compared with direct tail-recursive Fib.
Finally, it was incredible that the goal of tail recursion optimization was achieved.