Python 异常处理的最佳实践?

78 投票
5 回答
74070 浏览
提问于 2025-04-15 11:27

创建异常时有哪些最佳实践?我刚看到这个内容,不知道是该感到震惊,还是觉得不错。我在书里读到过,异常绝对不应该包含字符串,因为字符串本身也可能会引发异常。这是真的吗?

根据我对这些脚本的理解,这样做是为了让所有内部的Python库都有一个统一的错误信息格式(这真的是非常需要的),所以我能理解把错误信息字符串放进去是个好主意。(几乎每个方法都会抛出异常,因为我们绝对不希望无效的数据通过)。

这里提到的代码如下:

"""
Base Exception, Error
"""
class Error(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return "[ERROR] %s\n" % str(self.message)

    def log(self):
        ret = "%s" % str(self.message)
        if(hasattr(self, "reason")):
            return "".join([ret, "\n==> %s" % str(self.reason)])
        return ret

class PCSException(Error):
    def __init__(self, message, reason = None):
        self.message = message
        self.reason = reason
    def __str__(self):
        ret = "[PCS_ERROR] %s\n" % str(self.message)
        if(self.reason != None):
            ret += "[REASON] %s\n" % str(self.reason)
        return ret

这只是冰山一角,但有人能告诉我为什么这可能是个糟糕的主意吗?或者有没有更好的异常处理方式或风格?

5 个回答

12

我觉得不建议用字符串来创建异常的建议来源于《学习Python》(O'Reilly出版社)。在一个标题为字符串异常是不行的!的部分,它提到过(现在已经去掉了)直接用任意字符串来创建异常的能力。

它给出的示例代码是:

myexc = "My exception string"
try:
    raise myexc
except myexc:
    print ('caught')

这段内容在第四版(平装本)的第858页。

95

稳健的异常处理(在Python中) - 这是我之前写的一篇关于“Python异常处理最佳实践”的博客文章。你可能会觉得它很有用。

以下是博客中的一些关键点:

不要用异常来控制程序流程

异常是用来处理特殊情况的:那些不属于正常执行的事件。

比如说,在字符串上使用'find'方法,如果找不到模式,它会返回-1,但如果你试图访问字符串末尾之后的部分,就会抛出异常。找不到字符串是正常的执行情况。

在能处理异常的地方处理异常

...

最好的处理地点是那段能够处理异常的代码。对于一些异常,比如编程错误(例如IndexError、TypeError、NameError等),最好让程序员或用户来处理,因为“处理”这些异常只会掩盖真正的错误。

总是问自己“这里是处理这个异常的合适地方吗?”并且要小心捕获所有异常。

记录你的代码可能抛出的异常

...

考虑你的代码可能抛出的异常会帮助你写出更好、更安全和更封装的代码。

37

我在书里看到过好几次,异常(错误)绝对不应该包含字符串,因为字符串本身也可能会引发异常。这是真的吗?

啥意思?

请给个参考资料或者链接。这完全不对。

因为所有对象都可能引发异常,按照这个逻辑,任何对象都不能放在异常里。

不,在Python中说“不要用字符串”简直是疯了。也许你是在C++的上下文中看到的。


补充说明

很久很久以前(在古老的时代),你可以通过名字来引发Python异常,而不是通过实际的类。

raise "SomeNameOfAnExceptionClass"

这很糟糕。但这并不是说在异常中包含字符串。这是用字符串命名异常,而不是用实际的类对象。在2.5版本中,这仍然可以工作,但会有一个弃用警告。

也许这就是你看到的“不要用字符串名称引发异常”。

撰写回答