You're looking for tail call optimization, which is basically a technique to convert recursive programs to iterative without rewriting them. For example, if you call your factorial function with n = 1000, Python fails complaining that "maximum recursion depth exceeded". However, when you rewrite the function to be tail-recursive:
def tail_factorial(n, result=1):
if n <= 1:
return result
else:
return fac(n - 1, result * n)
and then use a "trampoline" to call it:
def trampoline_factorial(n):
def fac(n, result=1):
if n <= 1:
return result
else:
return lambda: fac(n - 1, result * n)
f = fac(n)
while callable(f):
f = f()
return f
you can evaluate 1000! without any problems.
Tail-call optimization can be indeed automated in Python using decorators, see e.g. here