有没有一种方法可以检查函数是否在python中是递归的?


问题内容

我想为一个练习编写一个测试功能,以确保正确实现一个功能。
所以我想知道,有没有一种方法,给定函数“ foo”,以检查是否以递归方式实现?
如果它封装了递归函数并使用它,它也将计数。例如:

def foo(n):
    def inner(n):
        #more code
        inner(n-1)
    return inner(n)

这也应被认为是递归的。
请注意,我想使用 外部 测试功能来执行此检查。无需更改功能的原始代码。


问题答案:

解:

from bdb import Bdb
import sys

class RecursionDetected(Exception):
    pass

class RecursionDetector(Bdb):
    def do_clear(self, arg):
        pass

    def __init__(self, *args):
        Bdb.__init__(self, *args)
        self.stack = set()

    def user_call(self, frame, argument_list):
        code = frame.f_code
        if code in self.stack:
            raise RecursionDetected
        self.stack.add(code)

    def user_return(self, frame, return_value):
        self.stack.remove(frame.f_code)

def test_recursion(func):
    detector = RecursionDetector()
    detector.set_trace()
    try:
        func()
    except RecursionDetected:
        return True
    else:
        return False
    finally:
        sys.settrace(None)

用法/测试示例:

def factorial_recursive(x):
    def inner(n):
        if n == 0:
            return 1
        return n * factorial_recursive(n - 1)
    return inner(x)


def factorial_iterative(n):
    product = 1
    for i in xrange(1, n+1):
        product *= i
    return product

assert test_recursion(lambda: factorial_recursive(5))
assert not test_recursion(lambda: factorial_iterative(5))
assert not test_recursion(lambda: map(factorial_iterative, range(5)))
assert factorial_iterative(5) == factorial_recursive(5) == 120

本质上,test_recursion它接受没有参数的可调用对象,对其进行调用,然后返回True该可调用对象在执行过程中的任何时候是否在堆栈中两次出现相同的代码,False否则返回。我认为这可能不是OP想要的。例如,可以很容易地对其进行修改,以测试同一代码在特定时刻是否在堆栈中出现了10次。