简体   繁体   English

Python 嵌套与链式 function 递归调用

[英]Python nested vs chained function calls in recursion

I am wondering about the output我想知道 output

sys: maxRecursionDepth = 10
f1, f2, f3, f4, f5, f1, 
 >>> maxRecursionDepth =  2
# -----------------------------
sys: maxRecursionDepth = 10
f1, f1, f1, f1, f1, f1, 
 >>> maxRecursionDepth =  6

of code provided below.下面提供的代码。

What I am wondering about is: What causes that chaining of function calls compared to nesting of function calls has different impact on the by the counter counted calls to the topmost function starting the recursion?我想知道的是:与 function 调用的嵌套相比,是什么原因导致 function 调用的链接对由计数器计数的对最顶层 ZC1C425268E68385D1AB5074ZA94F14 开始递归的调用有不同的影响? In other words, how does it come that nested calls don't reduce the depth of recursion like the chained calls do?换句话说,嵌套调用如何不像链式调用那样减少递归深度? All of the nested functions wait for their parameter being evaluated, so they should take space on the stack, but it seems that they don't.所有嵌套函数都等待其参数被评估,因此它们应该在堆栈上占用空间,但似乎它们没有。

from sys import getrecursionlimit, setrecursionlimit
setrecursionlimit(10)
print(f'sys: maxRecursionDepth = {getrecursionlimit()}')
cnt = 0
def f1():
    global cnt
    print('f1', end=', ')
    cnt += 1
    f2()
def f2():
    print('f2', end=', ')
    f3()
def f3():
    print('f3', end=', ')
    f4()
def f4():
    print('f4', end=', ')
    f5()
def f5():
    print('f5', end=', ')
    f1()
# ---
try:
    f1()
except RecursionError:
    print(f'\n >>> maxRecursionDepth =  {cnt}') # 200
    # RecursionError: maximum recursion depth exceeded

print('# -----------------------------')

#"""
from sys import getrecursionlimit, setrecursionlimit
setrecursionlimit(10)
print(f'sys: maxRecursionDepth = {getrecursionlimit()}')
cnt = 0
def f1():
    global cnt
    print('f1', end=', ')
    cnt += 1
    f2(f3(f4(f5(f1()))))
def f2(f):
    print('f2', end=', ')
    f(f3)
def f3(f):
    print('f3', end=', ')
    f(f4)
def f4(f):
    print('f4', end=', ')
    f5()
def f5(f):
    print('f5', end=', ')
    f1()
# ---
try:
    f1()
except RecursionError:
    print(f'\n >>> maxRecursionDepth =  {cnt}') # 996
    # RecursionError: maximum recursion depth exceeded

When you write当你写

f2(f3(f4(f5(f1()))))

it's roughly equivalent to它大致相当于

temp1 = f1()
temp2 = f5(temp1)
temp3 = f4(temp2)
temp4 = f3(temp3)
f2(temp4)

Each of the argument function calls is completed before calling the next one in the chain, so they don't add to the recursion depth.每个参数 function 调用在调用链中的下一个之前完成,因此它们不会增加递归深度。

In your second example, f2(f3(f4(f5(f1())))) , python will evaluate the innermost expression first.在您的第二个示例中, f2(f3(f4(f5(f1())))) , python 将首先评估最里面的表达式。 That's the recursive call f1() .这就是递归调用f1() And since f1 calls f1 again, f2 and etc... are never called.并且由于f1再次调用f1f2等......永远不会被调用。 Notice that only "f1" is printed.请注意,仅打印“f1”。

If you disassemble f1 , you'll see the byte codes如果你反汇编f1 ,你会看到字节码

   7          20 LOAD_GLOBAL              2 (f2)
             22 LOAD_GLOBAL              3 (f3)
             24 LOAD_GLOBAL              4 (f4)
             26 LOAD_GLOBAL              5 (f5)
             28 LOAD_GLOBAL              6 (f1)
             30 CALL_FUNCTION            0
             32 CALL_FUNCTION            1
             34 CALL_FUNCTION            1
             36 CALL_FUNCTION            1
             38 CALL_FUNCTION            1
             40 POP_TOP

CALL_FUNCTION calls the top thing on the execution queue. CALL_FUNCTION调用执行队列中的顶部事物。 So first you get f1 , then f2 , etc... (well, if you ever get that far).所以首先你得到f1 ,然后是f2 ,等等......(好吧,如果你能做到那么远)。

Python's "recursion count" is really a stack depth count. Python 的“递归计数”实际上是堆栈深度计数。 If it gets big, like 1000 calls big, that's likely a recursion problem, hence the name.如果它变得很大,比如 1000 个调用很大,那很可能是一个递归问题,因此得名。 In your first example, calls to f2 , etc increase the stack count faster than f1 increases the count.在您的第一个示例中,调用f2等增加堆栈计数的速度快于f1增加计数。 But in your second example, because f1 calls f1 before any other funtion, cnt goes up at the same rate as the stack count.但是在您的第二个示例中,因为f1在任何其他函数之前调用f1 ,所以cnt以与堆栈计数相同的速率上升。

The reason why you don't quite reach 10 is that there is already some stuff on the stack by the time your code runs.您没有完全达到 10 的原因是,在您的代码运行时,堆栈上已经有一些东西了。

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

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