Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 检测一个方法是否是递归的而不调用它?_Python_Unit Testing_Recursion_Inspect - Fatal编程技术网

Python 检测一个方法是否是递归的而不调用它?

Python 检测一个方法是否是递归的而不调用它?,python,unit-testing,recursion,inspect,Python,Unit Testing,Recursion,Inspect,这听起来可能是一件愚蠢的事情。上下文是测试驱动的开发:我有一种方法,它涉及到通过树的节点进行下一步操作,为了开发这个函数,我经历了: “查看子节点”“如果子节点有子节点,则查看孙子节点”“如果孙子节点有子节点,则查看曾孙节点”。。。等等 因此,您必须用递归方法替换此代码。如果您使用的是TDD,那么您希望编写一条断言语句,如果您的方法不是递归的,则该语句将失败。对于非TDD的人来说,这可能听起来很愚蠢,但有一点是,树通常涉及相当多的递归功能,因此跳过这种测试步骤实际上感觉“不好” 我想知道insp

这听起来可能是一件愚蠢的事情。上下文是测试驱动的开发:我有一种方法,它涉及到通过树的节点进行下一步操作,为了开发这个函数,我经历了:
“查看子节点”
“如果子节点有子节点,则查看孙子节点”
“如果孙子节点有子节点,则查看曾孙节点”。。。等等

因此,您必须用递归方法替换此代码。如果您使用的是TDD,那么您希望编写一条断言语句,如果您的方法不是递归的,则该语句将失败。对于非TDD的人来说,这可能听起来很愚蠢,但有一点是,树通常涉及相当多的递归功能,因此跳过这种测试步骤实际上感觉“不好”


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

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

一个简单的递归函数将查找具有相同名称的全局函数并调用它,因此您必须查看函数字节码或将字节码解析为AST,然后尝试查找对具有相同名称的全局对象的调用。但是,如果正在使用某个方法或函数有别名,您将面临更困难的检测任务

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

也许您希望避免递归,因为可能会耗尽堆栈。在这种情况下,您需要测试是否会耗尽堆栈


将堆栈深度设置为一个较小的数字(使用),创建一个比堆栈具有更多级别的树,然后尝试解析它。如果抛出
运行时错误
异常,则说明您使用的是递归或另一种过度依赖Python调用堆栈的方法。

即使在执行“TDD”时,检查方法是否是递归的也不是一个好主意。想一想,即使你能发现这个方法是递归的,但递归代码可能有一千种错误

相反,在进行TDD时,对您将要处理的数据集提出一个小而好的表示形式,并编写案例以检查您正在编写的函数是否能够很好地处理它们

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

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

这里有一些测试数据案例我会考虑测试<代码>函数而不是测试<代码>实现<代码>函数:

阳性测试以确保总数正确

  • 当我在树中有一个节点时,是否总正确
  • 当我有一个节点和两个一级子节点时,总数是否正确
  • 当我只有一个三分之一级的右孩子(左孩子缺失)是完全正确的 .
  • 然后测试一些退出条件:

  • 使用示例树初始化测试,并根据您希望实现的算法检查您的函数是否存在于预期节点上 .
  • 添加一些阴性测试

  • 如果树结构中存在循环,请检查抛出的异常 .
  • 等等。。。直到你涵盖了一些基本的组合。上升两个2级深

    现在您知道,要通过这些测试,您的函数必须正确执行
    操作,递归与否。这是单元测试的目的。测试功能,而不是实现的详细信息。


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

    当某人使用堆栈实现(正确的)树遍历函数时,测试结果会发生什么变化?你确定这就是你想要测试的吗?你通常测试功能,而不是具体的实现。你为什么关心它是否是递归实现的?@goncalopp抱歉,我真的不明白你的意思…@jonsharpe:根据我尝试采用的TDD方法/理念,应用程序代码的每个新步骤都必须以失败的断言开始!事实上,我并不在乎它是否是递归的。可以采用遍历的方法,但我只是想找到一个测试,如果方法不是递归的,它就会失败…谢谢。。。我是TDD新手,尝试自学,部分使用了“TDD使用Python”一书。本书区分了“功能测试”和“单元测试”。作者通过说功能测试从应用程序用户的PoV测试东西来描述差异,而单元测试从程序员的PoV测试东西。本书的“哲学”是,开发的每一步(理想情况下)都应该首先从失败的测试开始。这很难,但它似乎产生了强劲的结果!顺便说一句,我并不是特别想避免递归。@MikCorvent:函数的实现方式对两个焦点都没有关系。最终用户不在乎,他们只是想要一个工作程序。为了保持测试的灵活性,您希望单元测试只测试功能,而不是特定的实现。这样,您可以轻松地交换实现,并且仍然使用现有测试测试新的实现。谢谢,这很有意义。谢谢。。。是的,便士开始下降了!