|
5 | 5 | ----------
|
6 | 6 | 问题
|
7 | 7 | ----------
|
8 |
| -You’re building an application and would like to wrap lower-level exceptions with cus‐ |
9 |
| -tom ones that have more meaning in the context of your application. |
| 8 | +在你构建的应用程序中,你想将底层异常包装成自定义的异常。 |
10 | 9 |
|
11 | 10 | |
|
12 | 11 |
|
13 | 12 | ----------
|
14 | 13 | 解决方案
|
15 | 14 | ----------
|
16 |
| -Creating new exceptions is easy—just define them as classes that inherit from Excep |
17 |
| -tion (or one of the other existing exception types if it makes more sense). For example, |
18 |
| -if you are writing code related to network programming, you might define some custom |
19 |
| -exceptions like this: |
| 15 | +创建新的异常很简单——定义新的类,让它继承自 ``Exception`` (或者是任何一个已存在的异常类型)。 |
| 16 | +例如,如果你编写网络相关的程序,你可能会定义一些类似如下的异常: |
20 | 17 |
|
21 |
| -class NetworkError(Exception): |
22 |
| - pass |
| 18 | +.. code-block:: python |
23 | 19 |
|
24 |
| -class HostnameError(NetworkError): |
25 |
| - pass |
| 20 | + class NetworkError(Exception): |
| 21 | + pass |
26 | 22 |
|
27 |
| -class TimeoutError(NetworkError): |
28 |
| - pass |
| 23 | + class HostnameError(NetworkError): |
| 24 | + pass |
29 | 25 |
|
30 |
| -class ProtocolError(NetworkError): |
31 |
| - pass |
| 26 | + class TimeoutError(NetworkError): |
| 27 | + pass |
32 | 28 |
|
33 |
| -Users could then use these exceptions in the normal way. For example: |
| 29 | + class ProtocolError(NetworkError): |
| 30 | + pass |
34 | 31 |
|
35 |
| -try: |
36 |
| - msg = s.recv() |
37 |
| -except TimeoutError as e: |
38 |
| - ... |
39 |
| -except ProtocolError as e: |
40 |
| - ... |
| 32 | +然后用户就可以像通常那样使用这些异常了,例如: |
| 33 | + |
| 34 | +.. code-block:: python |
| 35 | +
|
| 36 | + try: |
| 37 | + msg = s.recv() |
| 38 | + except TimeoutError as e: |
| 39 | + ... |
| 40 | + except ProtocolError as e: |
| 41 | + ... |
41 | 42 |
|
42 | 43 | |
|
43 | 44 |
|
44 | 45 | ----------
|
45 | 46 | 讨论
|
46 | 47 | ----------
|
47 |
| -Custom exception classes should almost always inherit from the built-in Exception |
48 |
| -class, or inherit from some locally defined base exception that itself inherits from Ex |
49 |
| -ception. Although all exceptions also derive from BaseException, you should not use |
50 |
| -this as a base class for new exceptions. BaseException is reserved for system-exiting |
51 |
| -exceptions, such as KeyboardInterrupt or SystemExit, and other exceptions that |
52 |
| -should signal the application to exit. Therefore, catching these exceptions is not the |
53 |
| - |
54 |
| -intended use case. Assuming you follow this convention, it follows that inheriting from |
55 |
| -BaseException causes your custom exceptions to not be caught and to signal an im‐ |
56 |
| -minent application shutdown! |
57 |
| -Having custom exceptions in your application and using them as shown makes your |
58 |
| -application code tell a more coherent story to whoever may need to read the code. One |
59 |
| -design consideration involves the grouping of custom exceptions via inheritance. In |
60 |
| -complicated applications, it may make sense to introduce further base classes that group |
61 |
| -different classes of exceptions together. This gives the user a choice of catching a nar‐ |
62 |
| -rowly specified error, such as this: |
63 |
| - |
64 |
| -try: |
65 |
| - s.send(msg) |
66 |
| -except ProtocolError: |
| 48 | +自定义异常类应该总是继承自内置的 ``Exception`` 类, |
| 49 | +或者是继承自那些本身就是从 ``Exception`` 继承而来的类。 |
| 50 | +尽管所有类同时也继承自 ``BaseException`` ,但你不应该使用这个基类来定义新的异常。 |
| 51 | +``BaseException`` 是为系统退出异常而保留的,比如 ``KeyboardInterrupt`` 或 ``SystemExit`` |
| 52 | +以及其他那些会给应用发送信号而退出的异常。 |
| 53 | +因此,捕获这些异常本身没什么意义。 |
| 54 | +这样的话,假如你继承 ``BaseException`` |
| 55 | +可能会导致你的自定义异常不会被捕获而直接发送信号退出程序运行。 |
| 56 | + |
| 57 | +在程序中引入自定义异常可以使得你的代码更具可读性,能清晰显示谁应该阅读这个代码。 |
| 58 | +还有一种设计是将自定义异常通过继承组合起来。在复杂应用程序中, |
| 59 | +使用基类来分组各种异常类也是很有用的。它可以让用户捕获一个范围很窄的特定异常,比如下面这样的: |
| 60 | + |
| 61 | +.. code-block:: python |
| 62 | +
|
| 63 | + try: |
| 64 | + s.send(msg) |
| 65 | + except ProtocolError: |
| 66 | + ... |
| 67 | +
|
| 68 | +你还能捕获更大范围的异常,就像下面这样: |
| 69 | + |
| 70 | +.. code-block:: python |
| 71 | +
|
| 72 | + try: |
| 73 | + s.send(msg) |
| 74 | + except NetworkError: |
| 75 | + ... |
| 76 | +
|
| 77 | +如果你想定义的新异常重写了 ``__init__()`` 方法, |
| 78 | +确保你使用所有参数调用 ``Exception.__init__()`` ,例如: |
| 79 | + |
| 80 | +.. code-block:: python |
| 81 | +
|
| 82 | + class CustomError(Exception): |
| 83 | + def __init__(self, message, status): |
| 84 | + super().__init__(message, status) |
| 85 | + self.message = message |
| 86 | + self.status = status |
| 87 | +
|
| 88 | +看上去有点奇怪,不过Exception的默认行为是接受所有传递的参数并将它们以元组形式存储在 ``.args`` 属性中. |
| 89 | +很多其他函数库和部分Python库默认所有异常都必须有 ``.args`` 属性, |
| 90 | +因此如果你忽略了这一步,你会发现有些时候你定义的新异常不会按照期望运行。 |
| 91 | +为了演示 ``.args`` 的使用,考虑下下面这个使用内置的 `RuntimeError`` 异常的交互会话, |
| 92 | +注意看raise语句中使用的参数个数是怎样的: |
| 93 | + |
| 94 | +:: |
| 95 | + |
| 96 | + >>> try: |
| 97 | + ... raise RuntimeError('It failed') |
| 98 | + ... except RuntimeError as e: |
| 99 | + ... print(e.args) |
67 | 100 | ...
|
| 101 | + ('It failed',) |
| 102 | + >>> try: |
| 103 | + ... raise RuntimeError('It failed', 42, 'spam') |
| 104 | + ... except RuntimeError as e: |
68 | 105 |
|
69 |
| -It also gives the ability to catch a broad range of errors, such as the following: |
70 |
| - |
71 |
| -try: |
72 |
| - s.send(msg) |
73 |
| -except NetworkError: |
| 106 | + ... print(e.args) |
74 | 107 | ...
|
| 108 | + ('It failed', 42, 'spam') |
| 109 | + >>> |
75 | 110 |
|
76 |
| -If you are going to define a new exception that overrides the __init__() method of |
77 |
| -Exception, make sure you always call Exception.__init__() with all of the passed |
78 |
| -arguments. For example: |
79 |
| - |
80 |
| -class CustomError(Exception): |
81 |
| - def __init__(self, message, status): |
82 |
| - super().__init__(message, status) |
83 |
| - self.message = message |
84 |
| - self.status = status |
85 |
| - |
86 |
| -This might look a little weird, but the default behavior of Exception is to accept all |
87 |
| -arguments passed and to store them in the .args attribute as a tuple. Various other |
88 |
| -libraries and parts of Python expect all exceptions to have the .args attribute, so if you |
89 |
| -skip this step, you might find that your new exception doesn’t behave quite right in |
90 |
| -certain contexts. To illustrate the use of .args, consider this interactive session with the |
91 |
| -built-in RuntimeError exception, and notice how any number of arguments can be used |
92 |
| -with the raise statement: |
93 |
| - |
94 |
| ->>> try: |
95 |
| -... raise RuntimeError('It failed') |
96 |
| -... except RuntimeError as e: |
97 |
| -... print(e.args) |
98 |
| -... |
99 |
| -('It failed',) |
100 |
| ->>> try: |
101 |
| -... raise RuntimeError('It failed', 42, 'spam') |
102 |
| -... except RuntimeError as e: |
103 |
| - |
104 |
| -... print(e.args) |
105 |
| -... |
106 |
| -('It failed', 42, 'spam') |
107 |
| ->>> |
108 |
| - |
109 |
| -For more information on creating your own exceptions, see the Python documentation. |
| 111 | +关于创建自定义异常的更多信息,请参考`Python官方文档 <https://docs.python.org/3/tutorial/errors.html>`_ |
0 commit comments