【问题标题】:Python recursive call inside a loop. How does it work?循环内的 Python 递归调用。它是如何工作的?
【发布时间】:2014-03-15 10:56:35
【问题描述】:

我遇到了一个内部带有递归函数调用的循环,其中循环的起始范围按如下方式递增。代码输出如下序列。但是,我无法概念化为什么会生成这个特定序列。有人可以对其工作有所了解。以及将这个递归函数转换为输出相同序列的迭代函数有多可行。请帮忙。

代码:

def foo(step=0):
    for i in range(step, 4):
        print step
        foo(step+1)

foo()   

输出:

0 1 2 3 2 3 1 2 3 2 3 1 2 3 2 3 0 1 2 3 2 3 1 2 3 2 3 1 2 3 2 3 0 1 2 3 2 3 1 2 3 2 3 1 2 3 2 3 0 1 2 3 2 3 1 2 3 2 3 1 2 3 2 3

类似设计的代码来查找 Anagrams:

def find_anagrams(word, step=0):
    print 'step->', step
    if step == len(word):
        print "".join(word)
    for i in range(step, len(word)):
        print step, i
        word_ = list(word)
        word_[step], word_[i] = word_[i], word_[step]
        find_anagrams(word_, step+1)

【问题讨论】:

  • 我对这类事情的概念化方法是在纸上手动执行程序,记下变量的值。
  • 按调用深度缩进输出会让它更容易理解。例如:ideone.com/g0ludx
  • 没错!我试着这样做。可能是我错过了一些东西。请提供一些启示。
  • Hint print range(step, 4) for 循环之前。
  • 硬编码迭代版本:ideone.com/cILsb1

标签: python loops python-2.7 recursion iteration


【解决方案1】:

我认为可以通过使用 stdlib 重构您的字谜代码以避免递归循环:

from itertools import permutations

def anagrams (word):
    anagrams = set ()
    for p in permutations (word):
        anagram = ''.join (p)
        anagrams |= {anagram}
    return anagrams

def isAnagram (word1, word2):
    return sorted (word1) == sorted (word2)

【讨论】:

  • 是的!我明白那个。但我的问题是循环内的递归调用如何生成这样的序列。我需要对函数调用有所了解。
  • PEP 8:在以下情况下避免多余的空格:...紧接在开始函数调用的参数列表的左括号之前...
  • @falsetru 是正确的,见第三条:python.org/dev/peps/pep-0008/#pet-peeves
  • @falsetru 我认为 PEP 的这一部分标题为“Pet Peeves”很有趣。恰到好处。
  • @Hyperboreus,你好像说错人了;
【解决方案2】:

考虑 for 循环。您正在遍历range(step, 4)。如果step = 0 则迭代[0,1,2,3],如果step = 1 则迭代[1,2,3] 等等。 每次调用 foo(step) 时,它都会迭代该范围 - 但当前调用中迭代的范围不会改变。因此,对于第一个循环,您会得到从 0 到 3 的迭代,第二个循环是 1-3,依此类推。

为什么会这样打印?观察。

for i in range(0,4):
    print 0
    for j in range(1,4):
        print 1
        for k in range(2,4):
            print 2
            for h in range(3,4):
                 print 3

这将与您的递归函数具有相同的输出

【讨论】:

    【解决方案3】:

    让我试试:

    从您的 sn-p 中,在每个函数调用中,即 foo(step+1) 一个称为激活记录的结构或 创建框架以存储有关该函数调用的进度的信息。 所以,当一个函数的执行导致一个嵌套的函数调用时,前一个调用的执行 被挂起,并且它的激活记录存储了源代码中控制流的位置 应在嵌套调用返回后继续。

    这里是主要部分:

    当 step == 4 时,依次为 range(4,4) == 空列表,该时间迭代不会发生,因此它将返回 没有。然后它将移动到上一帧,在那里它被停止并开始一个新的迭代和递归函数调用 直到范围(4,4)。

    注意:递归基本情况仅在 step == 4 时,即时间范围 (4,4) 并返回 None。

    每个recusion都需要一个基本情况,否则它将进入无限循环。

    所以,让我们看看递归跟踪:我添加i 以区分step 和迭代增量。

    # 1 def foo(step=0):
    # 2    for i in range(step, 4):
    # 3        print 'i: %d, step: %d' % (i,step)
    # 4        foo(step+1)
    # 5 foo()
    
    line 5
    line 1  foo with step=0  which is default
    line 2  range(0,4)                       Frame: A,   0 is over, next=1
    line 3  step = 0            Output: i: 0, step: 0
    line 4  calling foo(0 + 1)
    line 1  foo with step=1
    line 2  range(1,4)                       Frame: B,   1 is over, next=2
    line 3  step = 1            Output: i: 1, step: 1
    line 4  calling foo(1 + 1)
    line 1  foo with step=2
    line 2  range(2,4)                       Frame: C,   2 is over, next=3
    line 3  step = 2            Output: i: 2, step: 2
    line 4  calling foo(2 + 1)
    line 1  foo with step=3
    line 2  range(3,4)                       Frame: D,   3 is over, next=4
    line 3  step = 3,           Output: i: 3, step: 3
    line 4  calling foo(3 + 1)
    line 1  foo with step=4
    line 2  range(4,4)                       Frame: E,
             This is an empty list, so it won't come inside the loop, so return None.
             Come back to previous Frame: D, i=3 was used, now increment to 4. So, again range(4,4)
    line 2  range(4,4)          Empty list, from Frame: D, return None
             Come back to previous Frame C, now i=3, step was called with value 2
    line 2  range(2,4)
    line 3  step = 2            Output: i: 3, step: 2, why step == 2 because the function foo was called with step=2
    line 4  calling foo(2 + 1)
    line 1  foo with step=3
    line 2  range(3,4)
    line 3  step = 3,           Output : i: 3, step: 3
    line 4  calling foo(3 + 1)
    line 1  foo with step=4
    line 2  range(4,4)          Empty list again, not going inside the list, return None
    line 2  range(2,4)          From Frame: B, step was == 1, because the function foo was called with step=1
    line 3  step: 1             Output: i: 2, step: 1,  here i ==2, because this is the second iteration of Frame B.
    line 4  calling foo(1 + 1)
    line 1  foo with step=2
    line 2  range(2,4)
    line 3  step: 2            Output: i: 2, step: 2
    

    在此之后,它遵循相同的递归方式,直到迭代范围耗尽,即 range(4,4)

    如果有帮助,请告诉我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-19
      • 2011-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-19
      • 2012-05-17
      相关资源
      最近更新 更多