3年前我写了一篇文章Python classic, static, class and abstract methods,现在似乎到了更新的时候,今天我想来剖析和讨论 Python 异常。 剖析异常基础类Python 异常的基础类名为BaseException。这个类在程序和库中很少用,更多时候它被当成是异常的实现细节。为了了解异常是怎么实现的,我们可以阅读 CPython 源码中的Objects/exceptions.c文件。在这个文件中你可以看到 BaseException 类中定义的所有基础方法和异常的属性。而我们常用的 Exception 类则继承于BaseException,该类只包含如下代码: 另外一些直接继承 BaseException 的类是GeneratorExit、SystemExit 和KeyboardInterrupt。而其他内置的异常一般直接从 Exception 类中继承。你可以通过pydoc2 exceptions或者pydoc3 builtins 命令来查看整个异常的结构。 这里是在 Python 2 和 3 中通过这个脚本生成的内置异常继承结构图。 https://coyee.com/uploads/img/20160813/111701_AtY7.png(查看大图) https://coyee.com/uploads/img/20160813/111702_OPKJ.png(查看大图) BaseException.__init__签名是BaseException.__init__(*args)。这个初始化方法保存了许多参数,都传入到的args属性上。从exceptions.c的源代码中可以看出这一点,在Python2 与Python3中都是这样的: 只有BaseException.__str__方法用到了args属性。这个方法使用self.args将异常转换为字符串: 上面的代码转换为 Python是这样的: 因此,异常信息应该被当作唯一一个参数传入给BaseException.__init__方法。 正确的定义异常类正如你可能已经知道了,在Python中,异常有可能在任何地方被抛出。最基本的异常类叫Exception,它可用于程序的任何地方。在编码中,没有程序或库直接抛出Exception-这对我们来说还不够。 自从将所有的异常设计为都继承这个顶级的Exception类,这个类可以很方便的用于捕获所有异常: 为了合理准确的定义你的异常类,这里有一些规范与编程技巧,你可以做为参照: 必须继承 Exception类: class MyOwnError(Exception): pass 利用前面提到的BaseException.__str__: 它将传递给BaseException.__init__ 方法的第一个参数打印出来,所以通常在调用 BaseException.__init__ 方法时,只传递一个参数 . 当创建类库时,可以定义一个继承于Exception的基类.客户在使用类库时,会更方便的捕捉任何异常: 在编写任何关于shose的代码时,这段代码将会很有用,除了ShoeError.例如,Django 对异常并没有拆分的很细,这导致我们很难捕获 "Django抛出的任何异常". 提供关于异常的详细信息.这是很有价值的,它可以正确的记录日志,做进一步操作甚至恢复: 然后,任何代码都可以检查异常,并根据异常做进一步处理: 例如,这里检测到违反SQL外键约束时,利用Gnocchi抛出特定的应用程序异常(NoSuchArchivePolicy): 在需要的时候继承内置的异常类型.这将使编程变得更方便,不需要为你的程序或类库编写特定的异常: 这将允许更多程序在不知道你定义的异常类型情况下,使用通用方式来捕获异常.如果一个程序知道如何处理ValueError, 它将不需要任何特定的代码或修改。 本文由愚、dreampuff、coyee参与翻译。
End |