如何在 Python 中不处理异常
我看到很多人以错误的方式处理异常。也许这也适用于你。下面的情况是不是很眼熟?
您正在编写一些代码,但您知道您正在使用的库可能会引发异常。你不记得是哪一个,确切地说。在这一点上,使用所谓的包罗万象的块并继续有趣的东西是很诱人的。
目录
<导航>- 最糟糕的方法
- 捕获所有异常的更好方法
- 情况变得更糟
- 抓住你能处理的东西
- 结论
最糟糕的方法
你能做的最糟糕的事情是创建一个捕获任何东西的 try-except 块。包罗万象,我的意思是:
try: ... except: pass
像这样的包罗万象的块是不好的,因为:
- 您不知道可能会引发哪些其他异常(稍后会详细介绍)。
- 我们通过静默使用 pass 而不是记录错误来隐藏异常。
此外,一个空的 except 将捕获所有内容,包括 KeyboardInterrupt
(control + c), SystemExit
,甚至是 NameErrors
!这意味着不能干净地停止以下代码:
from time import sleep while True: try: print("Try and stop me") sleep(1) except: print("Don't.. stop.. me now!")
随意尝试。您需要关闭终端窗口或终止 Python 进程才能停止该程序。
捕获所有异常的更好方法
相反,当使用 except Exception
,虽然仍然是一种快速而肮脏的方法来捕获太多异常,但至少您可以正确停止正在运行的进程:
from time import sleep while True: try: print("Try and stop me") sleep(1) except Exception: print("Ok I'll stop!")
捕获 Exception
时 你不会抓住 SystemExit
, KeyboardInterrupt
和其他此类例外。你问这是为什么呢?
所有异常都继承自一个名为 BaseException
的类 .根据官方文档:“在 try
带有 except
的语句 子句提到特定类,该子句还处理从该类派生的任何异常类。”一个空的 except
相当于 except BaseException
,因此它将捕获所有可能的异常。
相比之下,类 Exception
定义为:“所有内置的、非系统退出的异常都派生自这个类。所有用户定义的异常也应该派生自这个类。”
情况变得更糟
在下面的示例中,我们使用 os 库来获取当前工作目录。然而,我肥大的小手指打错了:
import os try: working_dir = os.getcdw() print(working_dir) except: print('error')
因为 os.getcdw
不是 os 模块中的函数,会抛出 NameError。除了失败,except 子句将捕获错误,打印“错误”,尽管我们明显的拼写错误,程序仍将继续。不幸的是,这不能通过捕获 Exception
来解决 要么!
显然,我们从第一步开始的小技巧并不能解决我们所有的问题。那么应该 我们呢?
抓住你能处理的东西
关于异常经常听到的一句话是:catch what you can handle .许多开发人员都倾向于直接处理异常,而让异常传播到程序中实际可以处理它的部分通常会更好。
例如,考虑打开和加载文件的文本编辑器部分,我们称它为 OpenFile
班级。如果用户请求打开一个不存在的文件,您可以直接处理该错误,或者让它传播。
在这种情况下,最好将异常传播给调用者,因为 OpenFile
不知道这个异常对调用者有多糟糕。调用者可以通过多种方式处理这种情况:
- 它可以创建一个具有该名称的新文件并继续
- 也许调用者需要该文件存在,在这种情况下,它会显示一个错误对话框,通知用户该文件不存在。
无论哪种方式,它都不是 OpenFile
类来决定在 FileNotFoundError
的情况下要做什么 .
那么是否应该始终传播异常?不可以。可以在 FileOpen 类中处理的一个可能的异常是 TimeoutError
.例如,您可能希望重试几次,而不会因错误而打扰调用者。这是 OpenFile
的异常 可以处理,抓到重试就OK了。
结论
在任何情况下,您都不应捕获超过您可以处理的异常。一揽子除了块是错误和不可预测代码的秘诀。换句话说:抓住你能处理的。
如果你在编写代码时牢记“抓住你能处理的东西”,那么编写包罗万象的块就是违反所有规则。所以,请停止这样做。作为一个练习,您可以重新审视一些现有代码,看看是否可以利用这些新知识对其进行改进!
Python