I've been playing around with memoization and recursion in python 3.3
Ignoring the fact that python is the wrong language to be doing this in, I've found that I get inconsistent results between using functools.lru_cache
to memoize, and not using functools.lru_cache
I'm not changing the recursion limit - it stays at the default, which for me is 1000.
To test the problem, I've written up a simple recursive function to sum numbers from 1 through i
#!/usr/bin/python
def sumtil(i):
"""Recursive function to sum all numbers from 1 through i"""
# Base case, the sum of all numbers from 1 through 1 is 1...
if i == 1:
return 1
else:
return i+sumtil(i-1)
# This will not throw an exception
sumtil(998)
# This will throw an exception
sumtil(999)
Running this function normally, I can run sumtil(998)
comfortably without hitting the recursion limit. sumtil(999)
or above will throw an exception.
However, if I try decorating this function with @functools.lru_cache()
, the recursion limit exception is thrown 3 times earlier, when running sumtil(333)
#!/usr/bin/python
import functools
@functools.lru_cache(maxsize=128)
def sumtil(i):
"""Recursive function to sum all numbers from 1 through i"""
# Base case, the sum of all numbers from 1 through 1 is 1...
if i == 1:
return 1
else:
return i+sumtil(i-1)
# This will not throw an exception
sumtil(332)
# This will throw an exception
sumtil(333)
Being that 332*3 = 996, but 333*3 = 999, it appears to me that the lru_cache decorator is causing each level of recursion in my function to become three levels of recursion.
Why do I get three times as many levels of recursion when using functools.lru_cache
to memoize a function?
The “maximum recursion depth exceeded in comparison” error is raised when you try to execute a function that exceeds Python's built in recursion limit. You can fix this error by rewriting your program to use an iterative approach or by increasing the recursion limit in Python.
The maximum recursion depth in Python is 1000. You can change the limit by calling sys. setrecursionlimit() method. Consider this a dangerous action!
Try increasing the recursion limit ( sys. setrecursionlimit ) or re-writing your code without recursion. Return the current value of the recursion limit, the maximum depth of the Python interpreter stack. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python.
Typically, the stack will overflow after between 6,000 and 7,000 steps.
Because a decorator is an extra function, so it "uses" one level in the stack. Example:
>>> def foo(f):
... def bar(i):
... if i == 1:
... raise Exception()
... return f(i)
... return bar
...
>>> @foo
... def sumtil(i):
... if i == 1:
... return 1
... else:
... return i+sumtil(i-1)
...
>>> sumtil(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in bar
File "<stdin>", line 6, in sumtil
File "<stdin>", line 5, in bar
File "<stdin>", line 6, in sumtil
File "<stdin>", line 4, in bar
Exception
>>>
Besides, if the decorator uses argument packing/unpacking, then an extra level is used (though I'm not knowledgeable enough about the Python runtime to explain why that happens).
def foo(f):
def bar(*args,**kwargs):
return f(*args,**kwargs)
return bar
Max. recursion depth exceeded:
1000
500
334
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With