A Cool Idear-> Python tail recursion optimization, idear-python
It's cool to share it with a foreign website. In general, Python and Java, C # do not have the ability to automatically optimize tail recursion. recursive calls are widely criticized for being limited by the call stack length, however, this madman solved this problem with an incredible method and implemented it in Python. From then on, Python's recursive call no longer needs to be restricted by the call stack length, which is so cool.
First, let's start with recursion. Before that, I wrote an article about recursive process and recursive optimization, which uses the Fibonacci number as an example. the linear recursive algorithm is passed out because it is too inefficient. Let's first look at the call in the method of delivery at the end:
1 def Fib (n, b1 = 1, b2 = 1, c = 3 ):
2 if n <3:
3 return 1
4 else:
5 if n = c:
6 return b1 + b2
7 else:
8 return Fib (n, b1 = b2, b2 = b1 + b2, c = c + 1)
9
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)
Bytes
>>>
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 Fib
RuntimeError: maximum recursion depth exceeded
>>>
Now let's optimize the tail recursion.
Add a Decorator to the Fib function, as shown below:
1 @ tail_call_optimized
2 def Fib (n, b1 = 1, b2 = 1, c = 3 ):
3 if n <3:
4 return 1
5 else:
6 if n = c:
7 return b1 + b2
8 else:
9 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:
1 import sys
2
3 class TailRecurseException:
4 def _ init _ (self, args, kwargs ):
5 self. args = args
6 self. kwargs = kwargs
7
8 def tail_call_optimized (g ):
9 """
10 This function decorates a function with tail call
11 optimization. It does this by throwing an exception
12 if it is it's own grandparent, and catching such
13 exceptions to fake the tail call optimization.
14
15 This function fails if the decorated
16 function recurses in a non-tail context.
17 """
18 def func (* args, ** kwargs ):
19 f = sys. _ getframe ()
20 if f. f_back and f. f_back.f_back and f. f_back.f_back.f_code = f. f_code:
21 raise TailRecurseException (args, kwargs)
22 else:
23 while 1:
24 try:
25 return g (* args, ** kwargs)
26 couldn t TailRecurseException, e:
27 args = e. args
28 kwargs = e. kwargs
29 func. _ doc _ = g. _ doc __
30 return func
31
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.