在不调用方法的情况下检测到方法是递归的?

Detect that a method is recursive without calling it?

这听起来像是一件愚蠢的事情。上下文是测试驱动开发:我有一个方法涉及逐步通过树的节点,并开发这个功能我已经走了:
"look at child nodes"
"if child node has children, then look at grandchild nodes"
"if grandchild node has children, then look at great-grandchild nodes"...等等

所以你到了必须用递归方法替换此代码的地步。如果你正在使用 TDD,你想写一个断言语句,如果你的方法不是递归的,它就会失败。这对于非 TDD 的人来说可能听起来很愚蠢,但有一点是树通常涉及相当多的递归功能,所以实际上感觉 "bad" 跳过这种测试步骤!

我想知道 inspect 模块是否有我需要的东西...但我正在努力。在我看来,在理想的世界中,您可能希望检测这种递归性而不必实际调用该方法。

您无法可靠地检查函数是否使用递归,不。

一个简单的递归函数会查找一个具有相同名称的全局函数并调用它,因此您必须查看函数字节码或将字节码解析为 AST 并尝试找到对全局函数的调用具有相同名称的对象。但是,如果使用了 方法 或函数被别名化,那么您将面临更艰巨的检测任务。

此外,您通常测试被测对象的功能,而不是具体实现。测试想要的结果,而不是你如何产生这些结果。

也许您想避免递归,因为您可能 运行 出栈。在那种情况下,你会 测试你是否会 运行 出栈

将堆栈深度设置为较小的数字(使用sys.setrecursionlimit()),创建一个层数比堆栈多的树,然后尝试解析它。如果抛出 RuntimeError 异常,则说明您正在使用递归或其他过度依赖 Python 调用堆栈的方法。

即使在做 'TDD' 时,检查 方法是否是递归的也不是一个好主意。 想想看,即使你能发现那个方法是递归的该 递归代码 可能有上千处错误。

相反,在进行 TDD 时,想出小但很好的表示 data-set 您将要处理的情况,并编写案例以检查您正在编写的函数是否能很好地处理它们。

让我们考虑一个递归函数的例子来解析和找到树节点的总和。

def total(tree):
    if tree == None: return 0
    return total(tree.left) + total(tree.right) + tree.cargo

以下是一些我会考虑测试 functionality 而不是测试 implementation 函数的测试数据案例:

积极测试以确保总数正确

  1. 当我在树中有一个节点时,总的是正确的
  2. 当我有一个节点和两个一级 children 时,总数是否正确
  3. 当我只有三分之一的右child(左child缺失)是总正确 . .

然后测试一些退出条件:

  1. 使用示例树启动测试,并根据您希望实现的算法检查您的函数是否在预期节点上退出 . .

添加一些负面测试

  1. 如果树结构中存在循环,则检查抛出的异常 . .

等等......直到你掌握了一些基本的组合。向上两个 2 层深。

现在您知道要通过这些测试,您的函数必须做 right 事情,递归与否。而就是单元测试的一个目的。测试 功能 而不是 实现的细节。

一旦您确信您的测试是健壮的,并且通过这些测试的任何函数都是一个好函数,那么如何实现该函数就无关紧要了。它可能是也可能不是递归的,但是您在编写单元测试时不应该关心