异常简介
异常(Exception)
即程序执行过程中产生的预期以外的错误,例如有一个脚本 test.py
,其内容如下:
1
2
3
#!/bin/python3
print('2' + 2)
当执行该脚本时会产生如下异常:
1
2
3
4
5
[root@localhost ~] python3 test.py
Traceback (most recent call last):
File "test.py", line 3, in <module>
print('2' + 2)
TypeError: can only concatenate str (not "int") to str
上面打印的内容称为 异常栈
,以 File 开头的那一行指明了产生异常的位置(即 test.py 的第 3 行),接下来一行即产生异常的语句(即 print(‘2’ + 2)),最后一行为异常类型以及异常消息,通过查看异常栈可以准确定位到产生异常的代码位置并进行修复。
异常处理
try
Python 中使用 try
语句进行异常处理,其语法定义如下:
1
2
3
4
5
6
7
try_stmt ::= try1_stmt | try2_stmt
try1_stmt ::= "try" ":" suite
("except" [expression ["as" identifier]] ":" suite)+
["else" ":" suite]
["finally" ":" suite]
try2_stmt ::= "try" ":" suite
"finally" ":" suite
以下是一个简单的示例,该示例会一直等到用户输入一个整数为止,如果输入的不是整数,就会进入到 except 子句中执行 print 打印错误提示:
1
2
3
4
5
6
7
>>> while True:
... try:
... x = int(input("Please enter a number: "))
... break
... except ValueError:
... print("Oops! That was no valid number. Try again...")
...
except
except 后面的异常类型可以是多个,使用圆括号括起来,表示捕获其中任一异常类型:
1
except (RuntimeError, TypeError, NameError):
except 后面也可以不接异常类型,表示捕获任意异常:
1
2
except:
print("Some error occurred.")
except 后面还可以接一个 as
子句来保存异常实例,以便后续进行处理:
1
2
except OSError as err:
print("OS error: {0}".format(err))
try 后面也可以同时接多个 except 子句,当发生异常时会按照顺序从上往下匹配,如果其中某个 except 子句匹配上了,后面的 except 子句就会跳过:
1
2
3
4
5
6
7
8
9
10
11
12
13
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
当产生的异常属于某个 except 子句后面的异常类的子类时,也会被捕获,比如以下示例中由于 C 和 D 都是 B 的子类,所以最终打印结果将是 B B B
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except B:
print("B")
except C:
print("C")
except D:
print("D")
else
在 except 子句后面还可以接一个 else
子句(如果有多个 except,else 必须放在所有 except 后面),当没有异常发生时,才会进入到 else 子句:
1
2
3
4
5
6
try:
print('hello, world')
except:
print('error')
else:
print('no error')
finally
在 try 语句的最后(即 except 和 else 后面)还可以接一个 finally
子句,无论是否发生异常,最终都会进入 finally 子句,所以通常可以在 finally
子句中进行一些清理工作:
1
2
3
4
5
6
7
8
try:
print('hello, world')
except:
print('error')
else:
print('no error')
finally:
print('finished')
抛出异常
raise
语句可以主动抛出异常:
1
2
3
4
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: HiThere
raise
后面可以是一个异常类或者一个异常实例,如果接的是一个异常类则相当于无参数的异常类实例:
1
raise ValueError # 相当于 'raise ValueError()'
在 except
子句中还可以使用不接任何参数的 raise
语句,这样表示直接将 except 捕获的异常再次原样抛出:
1
2
3
4
5
6
7
8
9
10
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flew by!')
... raise
...
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: HiThere
自定义异常
Python 提供了很多了内置异常类,其继承关系如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
但是用户也可以自定义异常类,自定义异常类必须直接或间接的继承自 Exception
,通常一个异常类里边什么都不做,或者最多定义几个属性用于保存异常相关的信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
参考资料
- [Errors and Exceptions] : https://docs.python.org/3.5/tutorial/errors.html
- [Exception hierarchy] : https://docs.python.org/3.5/library/exceptions.html#bltin-exceptions