This article and the other comments here are interesting, but some are trying to be a bit too clever. The original article isn't too bad, but one of the other comments suggests re-writing the contents of the function at run time, which I really don't think is a practical suggestion (think about debugging such a thing).
If I wanted to do this in practice, I'd just write the trampoline out explicitly, unless I wanted to do it a huge number of times. Doing it this way only takes a couple of extra lines of code but I think that's worth it for the improvement in explicitness, which is a big help for future maintainers (possibly me!).
from functools import partial
def _tail_factorial(n, accumulator):
if n == 0:
return accumulator
else:
return partial(_tail_factorial, n - 1, accumulator * n)
def factorial(n):
result = partial(_tail_factorial, n, 1)
while isinstance(result, partial):
result = result()
return result