为什么我在 python 函数内运行递归的 if/else 语句会使循环执行两次,即使 while 循环被标记为停止?

问题描述 投票:0回答:1

下面是我编写的用于添加两个值的代码, 对于变量 i:'r' 是重新运行,并将 n1 设置为第一次运行的输出,'e' 是退出 while 循环,'f' 是使用新的 n1 和 n2 集运行递归函数。

我遇到的问题是,当我在第一次运行期间选择“f”运行递归并在接下来的运行中选择“e”希望结束 while 循环时,因为“e”触发循环运行的 FALSE 标志。然而,尽管我选择了“e”,但该程序第三次运行。救命!!

我是编码新手,这是我第一次在这里发帖,希望我的问题有意义:)

def rec():
     n1=None
     run=True
     while run:
         if n1 == None:
             n1=int(input('first number'))
         n2=int(input('second number'))
         out=n1+n2

         i=input(f'{out}enter r f or e')

         if i=='e':
             run=False
         elif i=='r':
             n1=out
         elif i=='f':
             rec()
rec()
python-3.x recursion calculator
1个回答
0
投票

递归中的一个常见误解是认为从一个调用返回会以某种方式展开整个递归调用链并将控制权返回给原始调用者。这是不正确的——您不能在返回调用堆栈的过程中跳过任何调用。从递归调用返回仅将控制权(弹出调用堆栈)返回给立即调用函数,该函数使用返回值从中断处恢复运行。

最重要的是,请记住每个调用都有自己的一组局部变量(状态),其他调用无法看到。

在这两种情况下,递归函数的行为与普通函数完全相同。在这些方面,递归函数没有什么特别之处。

有了这个背景上下文,让我们检查一下您的顶级调用。当您(作为用户)输入

f
来执行此块时:

elif i=='f':
    rec()

调用函数暂停执行并递归运行

rec()
。在新的子
rec()
调用中,
while
运行,您选择
e
打破循环并返回到调用者。

当顶层

rec()
调用恢复时,
while
循环的下一次迭代将执行,因为
run
仍然是该函数内的
True
。请记住,
run
是一个仅限于每个调用的纯局部变量,因此(现在不存在的)子调用将
run
设置为
False
对于父级来说并不重要。

总而言之,您当前的设计要求用户为您调用的每个

e
输入一个
rec()
。避免这种情况的最简单方法就是立即返回:

if i=='e':
    return
elif i=='r':
    n1=out
elif i=='f':
    return rec()

较少的布尔值可以减少可变(可修改)状态,这意味着程序更容易理解,因此在任何情况下摆脱

run
都是一个好主意。

综上所述,递归对于这个用例来说根本不合适。对于 Python 来说,这是令人困惑的、非惯用的,并且如果用户尝试进行超过 1000 次递归调用,最终将会崩溃。

由于您已经有一个循环,我建议在整个操作中使用它。比如:

def interactively_add_numbers():
    n1 = None

    while True:
        if n1 is None:
            n1 = int(input("first number: "))

        n2 = int(input("second number: "))
        result = n1 + n2

        response = input(
            f"result = {result}\n"
            "  'r' (rerun with result as n1)\n"
            "  'f' (start fresh)\n  'e' (exit)\n> "
        )

        if response == "e":
            return
        elif response == "r":
            n1 = result
        elif response == "f":
            n1 = None


interactively_add_numbers()

作为练习,我建议处理输入错误和类型错误。如果用户在需要数字的地方输入字母,则程序会异常崩溃。如果用户输入

'e'
'r'
'f'
以外的选项,程序会假设输入了
'r'
,这令人惊讶。

© www.soinside.com 2019 - 2024. All rights reserved.