Python 如何对非正数进行例外处理

Python how to make an exception for non positive numbers

如何在此处引发异常以捕获非正输入?现在如果我输入一个负数就不会打印任何东西

"""
Generate fibonacci sequence to the nth digit
"""
def fib(n):
    try:
        if n <= 0:
            raise Exception
        prev = 0
        curr = 1
        for terms in range(0, int(n)):
            nxt = prev + curr
            print str(curr),
            prev = curr
            curr = nxt
    except ValueError or Exception:
        new = raw_input("Invalid input. Please enter a positive integer: ")
        fib(new)

n = raw_input("Enter number of terms: ")
fib(n)

except ValueError or Exception

正确的语法是 except (ValueError, Exception),但请注意,由于所有异常都继承自 Exception,因此这可能会出现错误。

您最好不要引发并尝试捕获一般异常。 相反,提高已经捕获的 ValueError:

def fib(n):
    try:
        if n <= 0:
            raise ValueError
    .
    .
    .
    except ValueError:
        .
        .
        .

要捕获多种异常类型,请将它们放在一个元组中。 ValueError or Exception 是一个计算结果为 ValueError 的布尔表达式。

此外,您永远不应该引发异常,也不应该捕获它。定义您自己的自定义异常 class。

class NonNegativeNumber(Error):
    pass


...
except (ValueError, NonNegativeNumber):

但是,请注意,ValueError 似乎是在这里引发的一个完全有效的异常;您可能根本不需要更具体的 class。

我认为这里的核心问题是您的 fib 函数有两个完全独立的职责:

  1. 处理用户输入和验证;和
  2. 计算斐波那契数列。

从名字来看,我会说它应该只做#2!

相反,将您的程序结构化为:

def positive_integer():
    """Loops until the user enters a positive integer."""
    ...

def fib(n):
    """Prints first n Fibonacci numbers."""
    if n < 0:
        raise ValueError
    prev = 0
    curr = 1
    for terms in range(n):  # note simplification here
        nxt = prev + curr
        print str(curr),
        prev = curr
        curr = nxt

fib(positive_integer())

现在您有两个函数,每个函数都有明确的单一职责。这使得每一个都不那么复杂; range 调用现在更简单了,例如,因为它可以假设 n 已经是一个整数(如果不是,用户会得到一个明智的 TypeError 来告诉他们出了什么问题)。

positive_inputAsking the user for input until they give a valid response;为此,循环比递归更好。

作为进一步的重构,其实可以把这三行删掉

nxt = prev + curr
prev = curr
curr = nxt

只有一个:

prev, curr = curr, curr + prev

另请注意,一般而言,您应使 try 块尽可能短,而 except 子句应尽可能具体。这使它们在阅读代码 ("I think this one thing could go wrong, and in that case we can do this about it") 时更有用,并且意味着不会悄悄地忽略合法问题。特别是,你几乎不应该直接处理 Exception(在 raiseexcept 中),它的范围太广而无法有效处理。

正如 Jon 所说,将输入收集与核心 Fibonacci 计算分开是一种更好的设计策略。此外,使用简单循环通常比使用递归调用(在其自身内部调用函数)更好,除非你真的需要递归(例如,在处理递归数据结构时,如目录树)。

这是您的代码的修改版本。我做了一些其他的小改动。在 Python 中,我们不需要像 nxt 这样的临时变量来进行核心斐波那契计算。相反,我们使用元组赋值,这样我们就可以一步更新 curr 并将旧的 curr 保存到 prev

def input_positive_integer(prompt=''):
    """ Get a positive integer from the user """
    while True:
        try:
            n = int(raw_input(prompt))
            if n <= 0:
                raise ValueError
            break
        except ValueError:
            print "Invalid input.",
            prompt = "Please enter a positive integer: "
    return n

def fib(n):
    """ Print n terms of the Fibonacci sequence """
    prev, curr = 0, 1
    for terms in range(n):
        print curr,
        prev, curr = curr, prev + curr

n = input_positive_integer("Enter number of terms: ")
fib(n)

测试

Enter number of terms: -4
Invalid input. Please enter a positive integer: q
Invalid input. Please enter a positive integer: 2.5
Invalid input. Please enter a positive integer: 5
1 1 2 3 5