【问题标题】:Python – Breaking out of a deeply nested loop with `while`, `try`, `if`, and `except` statementsPython – 使用 `while`、`try`、`if` 和 `except` 语句打破深度嵌套的循环
【发布时间】:2015-05-20 04:47:46
【问题描述】:

这是我的代码,它在给定用户输入a, b, c 的情况下求解一个二次方程。但是,我想检查不正确的用户输入。如果用户输入除浮点数之外的任何内容,用户将面临print "Not a valid input. Try again.\n",然后是函数quadratic2() 的循环。然而,这个程序是一个更大程序的一部分,所以我希望用户可以选择输入"next" 来终止这个功能并继续前进。我的问题是我需要 3 个用户输入,但我希望 "next" 输入成为第一个输入 a。这工作得很好,直到用户输入一个随机字符串,导致ValueError。一旦发生这种情况,我的代码就不想循环回来检查输入是否为next。请帮我!我认为这段代码的嵌套方式让我很困惑。

def retest3():
    print "Type in another a, b, and c. Or type \"Next\" to move on."
def quadratic1():
    print ("This program calculates the zeroes of a quadratic equation."
    "\nPlease enter a, b, and c, hitting \"Enter\" after each one: ")
def quadratic2():
    while 1 == 1:
        a = (raw_input())
        if "next" == a.lower():
            ontonextthing()
            return 1 == 0
        else:
            try:
                a = float(a)
            except ValueError:
                print "Not a valid input. Try again.\n"
                quadratic2()
            try:
                b = float(raw_input())
            except ValueError:
                print "Not a valid input. Try again.\n"
                quadratic2()
            try:
                c = float(raw_input())
            except ValueError:
                print "Not a valid input. Try again.\n"
                quadratic2()

            if b**2-4*a*c>0:
                root1=(-b+math.sqrt(b**2-4*a*c))/(2*a)
                root2=(-b-math.sqrt(b**2-4*a*c))/(2*a)
                print ("First Root: {0}\nSecond Root: {1}".format(root1,root2))
            else:
                print ("The discriminant is negative, so your"
                " roots will contain \"i\".")
                disc1=(b**2-4*a*c)
                disc2=-disc1
                sqrtdisc2=(math.sqrt(disc2))/(2*a)
                b2=(-b)/(2*a)
                print ("{0} + {1}i".format(b2, sqrtdisc2))
                print ("{0} - {1}i\n".format(b2, sqrtdisc2))
        retest3()   

quadratic1()
quadratic2()

【问题讨论】:

  • 这似乎过于混乱。你看过argparse吗?挺好的docs.python.org/2.7/library/argparse.html
  • This post 显示了一种处理方法,但如果您必须这样做,则例外。
  • 感谢您的反馈。我没有检查这些建议,因为下面的答案使它按我的意愿工作。我知道这是非常混乱的代码,我会努力养成写得更整洁的习惯,但是为了我这个小程序的目的,我已经研究了一段时间并且很高兴它可以工作!跨度>

标签: python if-statement while-loop nested try-catch


【解决方案1】:

在用户输入随机字符串导致 ValueError 之前,这非常有效。一旦发生这种情况,我的代码就不想循环回来检查输入是否是下一个。

好像你想要continue statement:

        try:
            b = float(raw_input())
        except ValueError:
            print "Not a valid input. Try again.\n"
            continue

continue 语句将您带回到while 循环的开头(下一次迭代)。目前您正在调用quadratic2(),这会使您的函数递归,而不是您想要的。

因为它是递归的,所以当您收到异常时,它会退出当前函数,但是因为您使用的是递归,所以您只需返回到您在中间的上一个函数(这是同一个函数强>)。因此,您输入的下一个输入可能会被

解析
b = float(raw_input())

而不是

a = (raw_input())

【讨论】:

  • 谢谢!这现在有效!您能否再向我解释一下continue 与重新调用函数的工作方式有何不同?我想我有点明白了......
  • continue 告诉程序简单地停止 while 循环的当前迭代,并开始下一次迭代。而通过重新调用该函数,通过简单地将整个def quadratic2(): 复制到另一个位置调用它quadratic3(),并从quadratic2quadratic3 进行所有调用,可能更容易看出你做错了什么反而。现在你看到如果你退出quadratic3 你会回到quadratic2 的中间吗?
  • 啊,谢谢,我现在明白了!马丁·科内尼你是救星
  • 带有 for 循环的列表推导可以工作:[get_input() for i in range(3)] 然后def get_input(): float(raw_input())。确保您也将异常处理放在def input
  • 但是,由于您的第一个 raw_input 与第二个和第三个的逻辑不同,我不会真的推荐这种方法。
【解决方案2】:

解决问题的“真正”解决方案是首先不要使用深度嵌套的结构。深度嵌套的语句使您的代码难以阅读、难以测试、难以维护和重用。此外,您会倾向于重复代码,这很糟糕。尤其是在 Python 中,深度嵌套会导致您计算空格以使缩进正确,这真是令人头疼。

将您的代码分解为函数,并遵循“单一职责原则”,让一个函数只做一件事。这有几个优点:

  1. 您不必牢记太多事情。专注于一个小问题,然后解决它。
  2. 您始终可以在函数的早期使用return,因此在许多情况下可以避免嵌套。
  3. 您可以在函数中重用代码。
  4. 您没有重复的代码:如果您想更改特定行为,请更改一个函数,而不是一个函数中的多个位置。
  5. 您可以单独测试您的函数,确保它们执行正确的操作。

在您的情况下,quadratic2 函数做了很多事情:

  • 它运行一个“主循环”
  • 它读取用户输入的命令
  • 它调度命令
  • 它读取用户输入的值
  • 它处理无效的用户输入
  • 它进行计算
  • 它将结果显示给用户

现在我并不是说上面列出的每个细节都需要一个函数,但很明显这个函数做得太多了。

如何分解的示例:

  • 为主循环和调度命令创建一个函数。让命令(例如“next”)在单独的函数中处理。
  • 编写一个函数来读取用户的float,并调用此函数三次,而不是重复三次try...except 代码。这样做还有一个额外的好处,就是您可以增强此函数以循环运行,从而要求用户重复输入一个值,而不必像当前解决方案那样重新开始。

其他提示:

  • 不要在returnraisebreakcontinue 之后使用else。没有必要,因为无论如何都不会到达下一条语句,并且您可以保存一个嵌套级别。
  • 不要使用诸如1==11==0 之类的混淆表达式。这只是写TrueFalse 的复杂方式。在您的示例中,它应该改为 while Truereturn False

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    相关资源
    最近更新 更多