有没有办法判断我是否在Python中使用递归?

时间:2010-09-21 22:10:19

标签: python recursion functional-programming tree traversal

我正在编写一个函数来遍历用户的文件系统,并创建一个表示该目录的树(树实际上是Tkinter中的TreeView小部件,但这在功能上是一棵树)。

我能想到这样做的最好方法是递归。但是,我在函数中的一个案例要求我知道它是否是“原始”函数调用,在这种情况下文件没有父节点,或者它是否是“递归”函数调用,即一个已经调用的函数由函数本身创建,以便我可以为这些文件提供适当的父节点。

Python中有没有办法问一个函数,“嘿,你是递归的吗?”或者“嘿,你从哪里打来的电话?”

5 个答案:

答案 0 :(得分:7)

与其他语言几乎相同 - 在您的情况下,您将对父项的引用传递,并检查它是否为None。如果是这样,则创建一个正确的父节点。

答案 1 :(得分:4)

  

我在函数中的一个案例要求我知道它是否是“原始”函数调用,在这种情况下文件没有父节点

这似乎是一个特殊功能的过多工作的奇怪案例。你必须构建树 - 为什么你需要知道它附加在哪里?为什么不构建你负责的节点并返回它们呢?

def make_tree(path):
    return [
        make_tree(os.path.join(path, element))
        for element in get_elements(path)]

收到树后再走一趟树?

如果你真的想要整合它,只需传递父母:

def make_tree(path, parent_node = None):
    new_node = Node(...)
    for ....:
        make_tree(path+..., new_node)

    if parent_node is not None:
        parent_node.add(new_node)
    else:
        .....

答案 2 :(得分:1)

包含对父级或某些级别信息的引用以及对递归的调用应该是容易和常见的。

另一种方式(我不喜欢这种方式)是使用pythons inspect模块,它允许你检查例如调用堆栈。一个例子:

#!/usr/bin/env python

import inspect

def whocalled():
    return inspect.stack()[2][3]

def fib(n):
    print n, whocalled()
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

if __name__ == '__main__':
    fib(4)

会打印:

4 <module>
3 fib
2 fib
1 fib
0 fib
1 fib
2 fib
1 fib
0 fib

答案 3 :(得分:1)

您可以通过inspect模块访问内存堆栈。

import inspect

def whoami():
    '''Returns the function name of the caller.'''

    return inspect.stack()[1][3] #Stack data for the name of the function

def caller():
    '''Returns the caller of a function.'''

    return inspect.stack()[2][3] #Stack data for the name of whatever calls this

caller = caller()

如果您尝试从__main__调用索引,则会出现索引超出范围错误。

when the caller of the function != whoami() -> no longer recursing.

答案 4 :(得分:1)

我真的很想知道为什么你这么复杂。您可以简单地将函数拆分为递归和非递归部分!这是一个简单的例子:

def countdown(n):
    " original function "
    print "Ok, start the countdown (not recursive)"

    msg = "We are at"

    def recursive( x ):
        " recursive part "
        if x >= 0:
            print msg, x, "(recursive)"
            return recursive(x-1)

    return recursive(n)

countdown(10)

实际上你甚至不需要很多recursive函数的参数,因为它是一个闭包,可以使用你在命名空间中定义的任何东西。