在使用 PyCharm IDE 时,使用except:
无异常类型会触发 IDE 的提醒,该异常子句是Too broad
.
我应该忽略这个建议吗?还是 Pythonic 总是指定异常类型?
指定显式异常类型几乎总是更好。如果您使用裸except:
子句,您最终可能会捕获除您期望捕获的异常之外的异常 - 这可能会隐藏错误或在程序没有按照您的预期执行时使调试变得更加困难。
例如,如果您要向数据库中插入一行,您可能希望捕获一个表明该行已存在的异常,以便进行更新。
try:
insert(connection, data)
except:
update(connection, data)
如果您指定一个 bare except:
,您还会捕获一个表明数据库服务器已崩溃的套接字错误。最好只捕获您知道如何处理的异常 - 程序在异常点失败通常比继续但以奇怪的意外方式表现要好。
您可能想要使用裸机的一种情况except:
是您需要始终运行的程序的顶层,例如网络服务器。但是,您需要非常小心地记录异常,否则将无法找出问题所在。基本上,在一个程序中最多应该只有一个地方可以做到这一点。
所有这一切的一个必然结果是你的代码永远不应该这样做,raise Exception('some message')
因为它强制客户端代码使用except:
(或者except Exception:
几乎一样糟糕)。您应该定义一个特定于您要发出信号的问题的异常(可能继承自某些内置异常子类,如ValueError
or TypeError
)。或者你应该提出一个特定的内置异常。这使您的代码的用户能够小心地捕捉他们想要处理的异常。
您不应忽视口译员给您的建议。
来自 Python 的PEP-8样式指南:
捕获异常时,尽可能提及特定的异常,而不是使用裸的 except: 子句。
例如,使用:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
一个简单的 except: 子句将捕获 SystemExit 和 KeyboardInterrupt 异常,使使用 Control-C 中断程序变得更加困难,并且可以掩盖其他问题。如果要捕获所有表明程序错误的异常,请使用 except Exception: (bare except 等价于 except BaseException:)。
一个好的经验法则是将裸“除外”子句的使用限制在两种情况下:
如果异常处理程序将打印或记录回溯;至少用户会意识到发生了错误。如果代码需要做一些清理工作,然后让异常通过 raise 向上传播。尝试...终于可以成为处理这种情况的更好方法。
这不是 Python 特有的。
例外的全部意义在于尽可能地在问题发生的地方处理问题。
因此,您保留在特殊情况下可能触发问题和解决方案的代码彼此“相邻”。
问题是您无法知道一段代码可能引发的所有异常。您所知道的是,如果它是一个说找不到文件的异常,那么您可以捕获它并提示用户获取一个执行或取消该功能的用户。
如果你把它放在 try catch 周围,那么无论你的文件例程中存在什么问题(只读、权限、UAC,而不是真正的 pdf 等),每个人都会进入你的文件 not found catch 和你的用户正在尖叫“但它就在那里,这段代码是垃圾”
现在有几种情况你可能会抓住一切,但应该有意识地选择它们。
它们是捕获,撤消一些本地操作(例如创建或锁定资源,(例如打开磁盘上的文件进行写入),然后再次抛出异常,以在更高级别处理)
另一个你是你不在乎为什么会出错。以印刷为例。你可能有一个问题,说你的打印机有问题,请解决它,不要因为它而杀死应用程序。如果您的代码使用某种时间表执行一系列单独的任务,那么类似的徒劳无功,您不会希望整个事情都死掉,因为其中一个任务失败了。
注意 如果您执行上述操作,我不能推荐某种异常日志记录,例如足够高的 try catch log end。
你也会用它来捕捉例如Control-C,所以除非你再次“抛出”它,否则不要这样做。但是,在这种情况下,您应该使用“finally”。
始终指定异常类型,有很多类型是您不想捕获的,例如SyntaxError
,KeyboardInterrupt
等MemoryError
。
这是我使用的地方,除了没有类型
这是我的代码中未检查异常的主要用途
我总是添加这个,这样生产代码就不会溢出堆栈跟踪
我有两种方法:
我更喜欢这种方式,我发现更容易检测应该适当捕获哪些异常:当更高级别记录较低级别的异常时,我可以更好地“看到”问题
一些同事更喜欢这种方式,因为它在它们“所属”的较低级别函数中保留较低级别的异常。