【问题标题】:confusion about a python recursion function关于python递归函数的困惑
【发布时间】:2016-09-26 15:41:31
【问题描述】:

我在网上有一个print_backward功能码,但是我很困惑 关于它的工作原理和输出。

以下是我的代码。

def print_backward(num):
    if num == 10:
        return 
    num += 1
    print(num)
    print_backward(num)
    print("yeah")   
    print(num)
    print()

print_backward(6)

下面是输出。

7
8
9
10
yeah
10

yeah
9

yeah
8

yeah
7

我可以理解它是如何从 7 打印到 10,因为每次调用 递归,num += 1。

但我很困惑,一旦 num 达到 10,print_backward 应该 返回,然后完成。它不应该打印yeah 10,yeah 9,yeah 8,yeah 7. 为什么这段代码调用了return,怎么还能打印?这段代码是如何向后打印的,这意味着我为什么叫print(num),它 可以打印 10 到 7 吗?

【问题讨论】:

    标签: python recursion


    【解决方案1】:

    函数调用实际上是一个堆栈操作。而递归是函数调用的一种特殊情况。

    每次调用函数时,返回地址都会被压入栈中,当函数返回时,程序会从栈顶弹出返回地址,程序从栈顶继续执行。您可以在wikipedia中查看关于call stack的官方说明。

    对于你的例子,print_backward(7)先调用,然后下一条命令会入栈,然后当你调用print_backward(8)时,下一条命令会再次入栈,所以经过4次递归调用,堆栈将是这样的:

    +-------------------------+ <--- Stack top
    | num = 10, print("yeah") | \
    | num = 9,  print("yeah") |  |
    | num = 8,  print("yeah") |   >   Call stack
    | num = 7,  print("yeah") |  |
    +-------------------------+ /
    

    print_backward(10) 调用时,条件符合 if 条件 num == 10:。程序执行return 语句,栈顶的Return address 将被弹出,程序从那里开始,这意味着print('yeah') for num = 10 将被执行。对print_backward(10)的调用完成后,堆栈将从堆栈中弹出另一个返回地址,并执行print_backward(9)中的print('yeah')。此操作将在堆栈为空时结束,即不再有函数返回。

    【讨论】:

    • 很好的解释。非常感谢你,伙计。很详细,超级清晰。
    • 非常感谢您的宝贵时间。
    【解决方案2】:

    在第一次运行时,代码不会比对 print_backward(num) 的内部调用更进一步,即 4 次(就像无限递归)

    当参数达到 10 时,所有函数都返回并继续前进,打印调用它们的原始 num+1。

    首先打印最大的数字,因为数字较高的调用首先返回。

    【讨论】:

    • 非常感谢您的解释。很清楚。
    • 非常感谢您的宝贵时间。
    • 没问题!那些递归调用不是很直观。有时使用调试器会有所帮助。
    • 除了使用'print',我不知道其他的调试方法。你能推荐我一个调试器吗?
    • 我喜欢使用打印进行调试 :) 我已经尝试过pydb 几次,它与 gdb 非常相似。这里有一个新的重构版本:code.google.com/archive/p/pydbgr/downloads
    【解决方案3】:

    函数调用通过堆栈发生。

    您在 6 上调用 print_backward。所以堆栈将有 6。
    现在你在 7 上调用它 ---> 所以堆栈有 6,7,其中 7 是顶部。
    现在你在 8 上调用它 ----> 所以堆栈是 6,7,8
    现在在 9,所以堆栈是 6,7,8,9
    现在是 10,所以堆栈是 6,7,8,9,10。

    现在当函数返回时,它会从堆栈中弹出。
    所以,你在函数中使用参数 10。所以,你调用了 return,它从堆栈中弹出。现在堆栈是 6,7,8,9。
    现在它打印“是的”和 10(因为 num 是 9,我们之前做了 num = num + 1)。 现在它返回并弹出 9。现在堆栈是 6,7,8
    现在它打印出是和 9,因为 num 是 8,我们之前做了 num = num +1)。

    同样,它也会打印其他内容。

    【讨论】:

    • 非常感谢。 Stack 有助于我理解这段代码是如何工作的。非常感谢您的时间。
    • @OregonDuck :没问题
    【解决方案4】:

    对于您的情况 - print_backward(6) 需要 4 次调用(递归)才能达到返回条件,即 if num == 10 - 在这些调用期间打印的函数:

    7  # print_backward(6) - first call we made
    8  # print_backward(7) - recursive
    9  # print_backward(8) - recursive
    10 # print_backward(9) - recursive - inner most, where the return is executed 
    

    对于下一次递归调用print_backward(10),返回条件为真,并且函数开始返回(从最里面的调用开始) - 结果递归调用下面的行(第 6 行)被调用,即

    yeah # 4th call (inner most) returned
    10
    
    yeah # 3rd call returned
    9
    
    yeah # 2nd call returned
    8
    
    yeah # 1st call returned
    7
    

    调用堆栈视图可视化将是:

    print_backward(6)
    | 7 # num += 1 and then print(num)
    | print_backward(7)
    | | 8
    | | print_backward(8)
    | | | 9
    | | | print_backward(9)
    | | | | 10
    | | | | | print_backward(10)
    | | | | | | return 
    | | | | yeah # print("yeah")   
    | | | | 10   # print(num)
    | | | | ()   # print()
    | | | yeah
    | | | 9
    | | | ()
    | | yeah
    | | 8
    | | ()
    | yeah
    | 7
    | ()
    

    【讨论】:

    • 这是一个很棒的图表,可以回答我的问题。它让我非常了解我的代码的过程。非常感谢你,伙计。这真的很有帮助。非常感谢您的时间。
    【解决方案5】:

    当 print_backward(6) 被调用时

    1 check for 10
    2 increase 6 by one num = 7
    3 print 7
    4 call backward with 7
    

    for 6 print_backward 还没有完成,print_backward(7) 被压入栈顶。剩下的部分

    print("yeah")
    print(7)
    

    将在递归调用完成时执行。我在以下步骤中跳过检查 10。将包括在最后的步骤中。

    5 increase 7 by one num = 8
    6 print 8
    7 call backward with 8 (7 not completed)
    8 increase 8 by one num = 9
    9 print 9
    10 call backward with 9 (8 not completed)
    11 increase 9 by one num = 10
    12 print 10
    return is encountered  
    13 call backward with 10 (9 not completed)
    14 check for 10 and return. 9 will continue for the execution.
    15 in the execution of 9 num is 10 so yeah is printed and then 10 is printed and print_backward for 9 is completed. Similarly for 8 num is 9 which print yeah followed by 9 and so on.
    

    【讨论】:

    • 很好的解释。循序渐进,非常容易理解和理解。太感谢了。我相信我对递归有了更深的理解。非常感谢您的帮助和时间。
    猜你喜欢
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 2015-04-08
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多