Python中编写try except的最佳方式是什么?

3
假设我有以下代码片段:
r = requests.post(url, data=values, files=files)

由于这是进行网络请求,因此可能会从此行抛出许多异常。为了完整性,我还可以包括文件读取、发送电子邮件等操作。为了解决此类错误,我会

try:
  r = requests.post(url, data=values, files=files)
  if r.status_code != 200:
    raise Exception("Could not post to "+ url)
except Exception as e:
  logger.error("Error posting to " + url)

这种方法存在两个问题。

  1. 我刚刚处理了一个通用异常,不知道这行代码会引发哪个具体的异常,在Python中找到最佳方法是什么。
  2. 这使代码看起来很丑陋,这不符合Pythonic的风格,但只要它强大并处理所有情况就可以接受。

我想知道在Python中处理异常的最佳方法是什么。

4个回答

8

在Python或其他任何地方编写try-except的最佳方式是尽可能地“狭窄”。捕获比你想要处理的异常更多是一个常见问题!

特别是,至少我会将您的示例代码重写为以下内容:

try:
  r = requests.post(url, data=values, files=files)
except Exception as e:
  logger.error("Error posting to %r: %s" % (url, e))
  raise
else:
  if r.status_code != 200:
    logger.error("Could not to %r: HTTP code %s" % (url, r.status_code))
  raise RuntimeError("HTTP code %s trying to post to %r" % (r.status_code, url))

这包含了几个最佳实践,例如:详细的错误信息、总是重新引发你不知道如何特定处理的异常(在记录更多详细信息和异常信息后)、永远不要抛出像 Exception 这样通用的东西等。关键是,只能在可能的代码最狭窄的部分捕获异常,这就是 try / except 中的 else: 子句有用的地方!如果您期望并知道如何处理特定的异常,那么更好,您可以在通用的 except Exception 子句记录和重新引发之前放置其他 except ThisSpecificProblem as e: 子句。但是(根据 Python 之禅 - 在 Python 解释器提示下使用 import this!) -“错误不应该默默通过。//除非明确地消除。”... 您只应该“明确消除”您完全预期且完全知道如何处理的错误!

4
我刚处理了一个通用异常,不知道哪个确切的异常会被引发,请问在Python中找到它的最佳方法是什么?
像往常一样,答案是查看文档

如果出现网络问题(如DNS故障、拒绝连接等),Requests将引发ConnectionError异常。

如果HTTP响应无效,则Requests将引发HTTPError异常。

如果请求超时,则引发Timeout异常。

如果请求超过配置的最大重定向次数,则引发TooManyRedirects异常。

Requests显式引发的所有异常都继承自requests.exceptions.RequestException。

引发异常的代码(特别是如果有自定义异常)是有文档说明的。如果文档不明确,您还可以查看源代码

你的代码没问题,但是你应该避免使用通用的异常处理语句,因为这可能会隐藏代码中的其他问题。你应该只捕获那些你可以预测到的异常,然后让其他异常“上升”直到被捕获/记录。


2

好的,回答您的第一个问题,“这行代码会引发什么具体异常”,您只差一步。

您已经调用了except Exception as e,但是您没有使用ee包含有关异常的信息,所以只需添加一个小的打印语句。

print e

它就能工作了:

>>> try:
...     x = int(raw_input('Input: '))
... except Exception as e:
...     print e
... 
Input: 5t
invalid literal for int() with base 10: '5t'
>>> 

我不太明白你在第二句话中所询问的内容,你说它丑陋/不符合Python风格,但后来又说它没问题。是的,它没问题,而且在我看来也很符合Python风格。


我不知道为什么这个答案收到了负面评价,因为它似乎是这个问题的一个非常直接和恰当的答案。 - kartikg3
正如@A.J.所说,try/except是处理异常的最佳方式。如果您知道会发生什么类型的异常以及处理它们的步骤,那么只需捕获这些异常并处理它们即可。对于所有其他/默认/未知情况,请使用“Exceptions”作为默认异常。 - kartikg3

0

尽可能避免使用except Exception as e:

为了清晰起见,您可以创建一个自定义异常类来处理错误代码= 200的情况。

class PostingError(Exception):
    pass

然后只抛出PostingError异常。仅捕获此异常。如果捕获所有类型的异常,可能会捕获错误的信息。例如,即使是内存错误也可能被捕获并显示为“Error posting to URL”。

因此,最终代码应如下所示:

try:
  r = requests.post(url, data=values, files=files)
  if r.status_code != 200:
    raise PostingError("Could not post to "+ url)
except PostingError as e:
  logger.error(e)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接