/src/tail_recursion.py
https://bitbucket.org/pmatiello/tail-recursion · Python · 54 lines · 26 code · 13 blank · 15 comment · 7 complexity · 0774d8ce22955e8b9e930015f2ceaec5 MD5 · raw file
- '''
- Support for unlimited tail recursion for Python.
- @author: Pedro Matiello <pmatiello@gmail.com>
- '''
- from sys import _getframe as getframe
- from dis import opmap
- OPCODES = [chr(opmap['RETURN_VALUE']), chr(opmap['POP_TOP'])]
- class tail_recursive(object):
- """
- Tail recursion decorator.
- """
- def __init__(self, function):
- self.function = function
-
- def _is_tailcall(self, frame):
- """
- Analyze bytecode to verify whether the previous call is a tail call.
-
- References:
- 1. http://docs.python.org/release/2.7/library/dis.html#bytecodes
- 2. http://lambda-the-ultimate.org/node/1331#comment-15183
- """
- caller_frame = frame.f_back
- code = caller_frame.f_code.co_code
- ip = caller_frame.f_lasti
- return code[ip + 3] in OPCODES
- def __call__(self, *args, **kwargs):
-
- frame = getframe()
-
- if frame.f_back and frame.f_back.f_back and frame.f_back.f_back.f_code == frame.f_code and self._is_tailcall(frame):
- return _continue(self.function, *args, **kwargs)
-
- retval = self.function(*args, **kwargs)
- while (True):
- if (type(retval) == _continue):
- retval = retval.func(*retval.args, **retval.kwargs)
- else:
- return retval
- class _continue(object):
-
- def __init__(self, func, *args, **kwargs):
- self.func = func
- self.args = args
- self.kwargs = kwargs