简体   繁体   English

循环内的Python递归调用。 它是如何工作的?

[英]Python recursive call inside a loop. How does it work?

I came across a loop with a recursive function call inside, where the start range of loop is incremented as follows. 我遇到了一个内部带有递归函数调用的循环,其中循环的起始范围如下所述。 The code outputs the following sequence as below. 该代码输出以下序列,如下所示。 However, I unable to conceptualize why this particular sequence is generated. 但是,我无法概念化为什么生成此特定序列。 Can somebody throw some insight into its working. 有人可以对其工作发表一些见识吗? And how feasible is it to convert this recursive function into an iterative function outputting the same sequence. 将该递归函数转换为输出相同序列的迭代函数是多么可行。 Please help. 请帮忙。

Code: 码:

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

foo()   

Output: 输出:

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

Code of similar design to find 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)

Let me try: 让我尝试:

From your snippet, in every function call ie foo(step+1) a structure known as an activation record or frame is created to store information about the progress of that invocation of the function. 在您的代码段中,在每个函数调用(即foo(step + 1))中,都会创建一个称为激活记录或框架的结构,以存储有关该函数调用进度的信息。 So, When the execution of a function leads to a nested function call, the execution of the former call is suspended and its activation record stores the place in the source code at which the flow of control should continue upon return of the nested call. 因此,当函数的执行导致嵌套函数调用时,前一个调用的执行将被挂起,并且其激活记录将源代码中存储的位置存储在源代码中,在返回嵌套调用时,控制流应在该位置继续。

Here is the main part: 这是主要部分:

When step == 4, which in turns range(4,4) == empty list, that time iteration won't happen so it will return None. 当step == 4时,而range(4,4)==空列表,则该时间迭代不会发生,因此它将返回None。 Then it will move to the previous frame, where it was stopped and start a new iteration and recursive function call until range(4,4). 然后它将移至上一帧,在该处停止并开始新的迭代和递归函数调用,直到range(4,4)。

NB: Recursive base case is only when step == 4, that time range(4,4) and return None. 注意:递归基本情况仅在step == 4时,即时间范围(4,4)并返回None。

Every recusion needs a base case other wise it will goto infinite loop. 其他情况都需要一个基本案例,否则它将陷入无限循环。

So, lets see the recursive trace: I am adding i to differentiate the step and iterative increment. 因此,让我们看一下递归跟踪:我添加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

After this it follows the same recursive fashion, until the iterative range is exhuausted ie range(4,4) 此后,它遵循相同的递归方式,直到迭代范围被废除,即range(4,4)

Please let me know if that helps. 请让我知道是否有帮助。

I think your anagram code could be refactored avoiding the recursive loop, by using the stdlib: 我认为可以通过使用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)

Consider the for loop. 考虑for循环。 You are iterating through range(step, 4) . 您正在遍历range(step, 4) If step = 0 then you are iterating over [0,1,2,3] , if step = 1 then you are iterating over [1,2,3] and so on. 如果step = 0则迭代[0,1,2,3] ;如果step = 1则迭代[1,2,3] ,依此类推。 Each time foo(step) is called it iterates over that range - but the range being iterated over in the current call doesn't change . 每次调用foo(step)都会在该范围内进行迭代 - 但当前调用中要迭代的范围不会更改 So for the first loop you get an iteration from 0 to 3, the second loop is 1-3, etc. 因此,对于第一个循环,您会得到一个从0到3的迭代,第二个循环是1-3,依此类推。

Why does it print like that? 为什么这样打印? Observe. 观察。

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

This will have the same output as your recursive function 这将具有与递归函数相同的输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM