【问题标题】:Error with simple Python code简单的 Python 代码出错
【发布时间】:2015-06-24 22:27:09
【问题描述】:

我有一个简单的 python(2.7.3 版)代码,它的输出我无法弄清楚。代码提示用户输入分数(如果输入不是从 0 到 1 的数字,将继续这样做),确定字母等级,然后退出。代码如下:

def calc_grade():
    try:
        score = float(raw_input("Enter a score: "))
        if score > 1.0:
            print "Error: Score cannot be greater than 1."
            calc_grade()
    except:
        print "Error: Score must be a numeric value from 0 to 1."
        calc_grade()

    print "\nthe score is: %s" % (score)
    if score >= 0.9:
        print "A"
    elif score >= 0.8:
        print "B"
    elif score >= 0.7:
        print "C"
    elif score >= 0.6:
        print "D"
    else:
        print "F"
    return 0
calc_grade()

如果我运行这个脚本并尝试输入:1.5、h、0.8,那么我会得到以下输出:

Enter a score: 1.5
Error: Score cannot be greater than 1.
Enter a score: h
Error: Score must be a numeric value from 0 to 1.
Enter a score: 0.8

the score is: 0.8
B
Error: Score must be a numeric value from 0 to 1.
Enter a score: 0.7

the score is: 0.7
C

the score is: 1.5
A

如您所见,在输入有效值 (0.8) 后,脚本会打印出正确的等级 (B),但脚本并没有像我预期的那样结束。相反,它会打印出非数字值的错误消息,然后提示用户再次输入分数。如果我输入另一个有效分数(在本例中为 0.7),则脚本会打印出正确的成绩 (C),然后打印出第一个错误的输入 (1.5) 及其成绩 (A)。

在我的一生中,我无法弄清楚是什么导致了这种“功能”。有什么建议吗?

【问题讨论】:

  • 您的异常处理程序正在捕获 UnboundLocalError 以及您所期望的 ValueError

标签: python


【解决方案1】:

在发生任何错误时,您会再次递归调用calc_grade,因此如果您输入了无效的输入,您将有多次调用。相反,您应该迭代地处理错误错误:

def calc_grade():
    score = None
    while score is None:     
        try:
            score = float(raw_input("Enter a score: "))
            if score > 1.0:
                print "Error: Score cannot be greater than 1."
                score = None
        except:
            print "Error: Score must be a numeric value from 0 to 1."

    # If we reached here, score is valid,
    # continue with the rest of the code

【讨论】:

  • 啊,好点子。因此,如果我正确理解这一点,在第一个不正确的值之后,我将在第一次调用 calc_grade() 的其余部分完成之前调用 calc_grade()?如果是这样,那么要打印的第二条非数字消息是什么情况?看起来我可以在递归调用 calc_grade(); 之后通过 return 来解决这个问题;这种方法是否违反了代码开发的最佳实践?
【解决方案2】:

事情是这样的:

当您将值“h”传递给函数时,将“h”转换为 float 失败,这会引发 ValueError。您的except 语句捕获了错误,然后再次调用calcGrade()。这个新调用的参数为 0.8,并正常返回。当 .8 调用返回时,它将控制权返回给已接收“h”作为参数的调用。然后该调用继续执行其下一条指令:print "\nthe score is: %s" % (score)。由于转换为浮动失败,因此从未分配分数。因此,对calcGrade() 的调用会引发UnboundLocalError,然后它会被其调用者捕获,这是calcGrade() 的实例,它被传递了值1.5(正如@ZackTanner 指出的那样)。回想一下,“h”调用是从 try 块内部调用的。

【讨论】:

    【解决方案3】:

    递归对你不利,因为你在递归之后的函数中有额外的代码。 @Mureink 的答案是处理此问题的有效方法。另一个是让数据输入动作成为自己的功能:

    def get_input():
        try:
            score = float(raw_input("Enter a score: "))
            if score > 1.0:
                print "Error: Score cannot be greater than 1."
                return get_input()
        except ValueError:
            print "Error: Score must be a numeric value from 0 to 1."
            return get_input()
        return score
    
    def calc_grade():
        score = get_input()
        print "\nthe score is: %s" % (score)
        if score >= 0.9:
            print "A"
        elif score >= 0.8:
            print "B"
        elif score >= 0.7:
            print "C"
        elif score >= 0.6:
            print "D"
        else:
            print "F"
        return 0
    calc_grade()
    

    当用户输入有效值时,此技术会返回输入的值。如果没有,则返回调用get_input() 的值。这将所有递归堆叠起来,准备返回返回给它们的任何东西。当用户最终输入一个有效的响应时,整个递归堆栈崩溃,返回用户输入的有效答案。

    calc_grade 中对get_input() 的调用将一直处理,直到用户输入有效答案。届时get_input 将停止处理并将有效的用户输入返回给calc_grade,以便calc_grade 进行处理。

    【讨论】:

    • 谢谢,艾伦。我相信我对递归如何咬我有部分了解,但我仍然缺少一个细节(请参阅我对@Mureink 的回复)。
    • @Shaun 我编辑添加更多解释。希望这会有所帮助。
    【解决方案4】:

    您忘记了递归不会终止对函数的先前调用。因此,当您在错误中调用 calc_grade() 时,您会返回到原始的 calc_grade()print "the score is:",这就是它多次打印的原因。

    现在,要修复您的代码,我只需添加一些返回值:

    def calc_grade():
        try:
            score = float(raw_input("Enter a score: "))
            if score > 1.0:
                print "Error: Score cannot be greater than 1."
                calc_grade()
                return
        except:
            print "Error: Score must be a numeric value from 0 to 1."
            calc_grade()
            return    
        print "\nthe score is: %s" % (score)
        if score >= 0.9:
            print "A"
        elif score >= 0.8:
            print "B"
        elif score >= 0.7:
            print "C"
        elif score >= 0.6:
            print "D"
        else:
            print "F"
    calc_grade()
    

    Python 不需要你在 return 之后写任何东西,你可以使用它来简单地退出函数。

    我还建议使用str.format% 格式相对。

    这就是我不会过多修改代码的方式:

    def calc_grade():
        try:
            score = float(raw_input("Enter a score: "))
            if score > 1.0:
                raise TypeError
        except ValueError:
            print "Error: Score must be a numeric value from 0 to 1."
        except TypeError:
            print "Error: Score cannot be greater than 1."
        except:
            print "Error: Unexpected error, try again."
        else:
            if score >= 0.9:
                score = "A"
            elif score >= 0.8:
                score = "B"
            elif score >= 0.7:
                score = "C"
            elif score >= 0.6:
                score = "D"
            else:
                score = "F"
            print "the score is: {}".format(score)
            return
        calc_grade()
    
    calc_grade()
    

    【讨论】:

      【解决方案5】:

      首先,您不能在calc_grade() 内部调用。这将运行一堆错误。您只能调用一次,但可以根据需要打印多次。 第二tryexcept 可能不是最好的方法。尝试制作 class 并从那里制作函数。每次您的代码完成运行时,tryexcept 都会运行。 第三,如果您在这些数字中的任何一个之间运行一个数字,它将print 最大值之前的所有字母。我有与您的代码相似的代码,它计算 3 个人的分数。这是一个帮助您更好地理解错误和异常的网站。 https://docs.python.org/2/tutorial/errors.html

      这是我的代码
          劳埃德 = {
              “名称”:“劳埃德”,
              “作业”:[90.0, 97.0, 75.0, 92.0],
              “测验”:[88.0, 40.0, 94.0],
              “测试”:[75.0, 90.0]
          }
          爱丽丝 = {
              “名称”:“爱丽丝”,
              “作业”:[100.0, 92.0, 98.0, 100.0],
              “测验”:[82.0, 83.0, 91.0],
              “测试”:[89.0, 97.0]
          }
          泰勒= {
              “名称”:“泰勒”,
              “作业”:[0.0, 87.0, 75.0, 22.0],
              “测验”:[0.0, 75.0, 78.0],
              “测试”:[100.0, 100.0]
          }
      
      # Add your function below!
      def average(numbers):
          total = sum(numbers)
          total = float(total)
          return total/len(numbers)
      def get_average(student):
          homework_ave=average(student["homework"])
          quizzes_ave=average(student["quizzes"])
          tests_ave=average(student["tests"])
          return 0.1 * average(student["homework"]) + 0.3 *         average(student["quizzes"]) + 0.6 * average(student["tests"])
      def get_letter_grade(score):
          if 90 <= score:
              return "A"
          elif 80 <= score:
              return "B"
          elif 70 <= score:
              return "C"
          elif 60 <= score:
              return "D"
          else:
              return "F"
      print get_letter_grade(get_average(lloyd))
      def get_class_average(students):
          results = []
          for student in students:
              results.append(get_average(student))
          return average(results)
      students = [lloyd, alice, tyler]
      print get_class_average(students)
      print get_letter_grade(get_class_average(students))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-05-03
        • 1970-01-01
        • 2014-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-16
        相关资源
        最近更新 更多