【问题标题】:Is there a way to tell if I'm using recursion in Python?有没有办法判断我是否在 Python 中使用递归?
【发布时间】:2011-04-15 11:01:31
【问题描述】:

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

我能想到的最好的方法是递归。但是,我在函数中的一个案例要求我知道它是否是“原始”函数调用,在这种情况下文件没有父节点,或者它是否是“递归”函数调用,即调用由函数本身生成,这样我就可以给这些文件一个合适的父节点。

在 Python 中有什么方法可以询问一个函数,“嘿,你是递归的吗?”或者“嘿,你是从哪里打来的?”

【问题讨论】:

  • 是的。如果您使用递归,那么您正在使用递归。
  • 这与你的问题无关,只是一个想法,你试过os.walk吗?它是一个遍历目录并返回一个包含当前目录、所有目录名和所有文件名的三元组的生成器。只是一个建议。但否则请按照吉姆的回答。
  • 所有文件都有一个父节点。 “/”是所有的父级。
  • 我试过 os.walk,但它让我的生活变得非常复杂。它不太适合填充树。

标签: python recursion functional-programming tree traversal


【解决方案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 函数甚至不需要太多参数,因为它是一个闭包,可以使用您在其命名空间中定义的任何内容。

【讨论】:

    【解决方案2】:

    您可以通过inspectmodule 访问内存堆栈。

    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.
    

    【讨论】:

      【解决方案3】:

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

      这似乎是特定功能工作量过多的奇怪案例。您必须构建树 - 为什么需要知道它的连接位置?为什么不直接构建您负责的节点并返回它们?

      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:
              .....
      

      【讨论】:

      • 这太棒了。我什至没有想过使用列表推导。这来得正是时候,因为我正准备放弃整个功能,因为我觉得自己在搞砸事情。
      • 非常直观。这是一个很好的问题解决方案。
      • 我一直在尝试使用这个列表推导,但它得到的只是一堆嵌套的空列表。我怎样才能让它归还树?
      • @Rafe:你必须添加你想要包含的信息——现在它只创建列表。尝试返回 (path, make_tree(...)) 而不是 make_tree(...) 本身 - 你会注意到它是如何工作的。
      【解决方案4】:

      在调用递归的同时包含对父级或某些级别信息的引用应该是简单且常见的。

      另一种方法(不过我不喜欢)是使用 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
      

      【讨论】:

        【解决方案5】:

        与所有其他语言几乎相同 - 在您的情况下,您将引用传递给父级并检查它是否为无。如果是这样,您将创建一个适当的父节点。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-08
          • 2012-09-18
          • 1970-01-01
          • 2011-07-24
          • 1970-01-01
          相关资源
          最近更新 更多