python 使用 raise 处理异常,但为什么需要 runtimeerror

python exception handling with raise but why runtimeerror is needed

我正在尝试从 Python 一本书中理解这段代码。

def client(hostname, port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.connect((hostname, port))
    print('Client socket name is {}'.format(sock.getsockname()))

    delay = 0.1  # seconds
    text = 'This is another message'
    data = text.encode('ascii')
    while True:
        sock.send(data)
        print('Waiting up to {} seconds for a reply'.format(delay))
        sock.settimeout(delay)
        try:
            data = sock.recv(MAX_BYTES)
        except socket.timeout as exc:
            delay *= 2  # wait even longer for the next request
            if delay > 2.0:
                raise RuntimeError('I think the server is down') from exc
        else:
            break   # we are done, and can stop looping

    print('The server says {!r}'.format(data.decode('ascii')))

这一行:

raise RuntimeError('I think the server is down') from exc

我知道“raise”可以引发异常,而“exc”包含异常。但我不明白为什么我们需要“RuntimeError('I think the server is down')”。让我们的代码有这一行而不是只有“raise”语句有什么意义。

简而言之:

两者的输出不同:

raise

给出这个输出:

RuntimeError: No active exception to reraise #or whatever exception is active

鉴于:

raise RuntimeError('I think the server is down')

给出:

RuntimeError: I think the server is down

在后者中,您指定了一个运行时错误,而在第一个中,您只是 运行 来自异常的错误。

附加示例:

为了进一步解释,请考虑以下示例:

try:
    9/0
except ZeroDivisionError as e:
    raise

给出输出:

ZeroDivisionError: division by zero

鉴于:

try:
    9/0
except ZeroDivisionError as e:
    raise RuntimeError('I think the server is down') from e

此代码给出输出:

RuntimeError: I think the server is down

所以这是一种避免一个错误并引发另一个错误的方法。

为什么需要这样:

假设您有一个搜索文本文件的程序,并将某个数字除以它找到的文本文件的数量。如果找不到文件,它将尝试:some_number/num_files,即 some_number/0,它会给出 ZeroDivisionError。在这种情况下,您可能想要 raise FileNotFoundError。在这种情况下,您可以使用:raise FileNotFoundError('There are no text files in the specified folder.').

socket.timeoutOSError 的子类。无论出于何种原因,此代码的作者希望 client 在这种情况下提出 RuntimeError

这是一种常见的做法。一个包可能会在其代码的深处处理一堆不同类型的错误。但是这些例外与模块的用户有多相关——尤其是当包本身可能随时间变化时?将这些异常聚合成一个较小的、记录在案的异常集是有意义的。用户不需要捕获并弄清楚如何处理数十个含义不是很清楚的异常,该包可以完成繁重的工作并传回一组更友好的错误。

假设这个程序包有几种不同的方法从服务器获取数据,或者有几种不同的方法可以检测到已关闭的服务器。用户不关心这段代码是否超时,或者是否以其他方式检测到。可以想象分发服务器地址的中间件意识到有 none 可用。此代码中的“错误”是未记录详细错误,因此任何人都无法弄清楚发生了什么。

当然这只是猜测。我认为在您正在阅读的书中,它是有道理的。这是演示聚合异常的常见做法的演示代码。