异常# i/ t2 C! ]3 j- j2 g4 @
当你的程序中出现某些 异常的 状况的时候,异常就发生了。例如,当你想要读某个文件的时候,而那个文件不存在。或者在程序运行的时候,你不小心把它删除了。上述这些情况可以使用异常来处理。
0 ?" D9 z8 ~. n# O u3 L9 J' ] g% z' N0 }
假如你的程序中有一些无效的语句,会怎么样呢?Python 会引发并告诉你那里有一个错误,从而处理这样的情况。) T/ n3 F, ^$ l$ x1 e/ A
: B; g- h/ Z% ^& P/ r错误% U5 {# v' x/ s) r5 S+ E
- >>> Print 'Hello World'* E6 y* J6 k, L8 ^
- File "<stdin>", line 1
: _3 ~) u* v- P' l; K/ O% V - Print 'Hello World'
$ o/ h+ `$ ]9 K o" G" I4 R- t9 H1 Z - ^. |4 m1 r8 h: M$ W, H c
- SyntaxError: invalid syntax
, ?; F Z5 d* H/ ` - " Z, u( G; _9 {. `
- >>> print 'Hello World'+ q9 H- d. F+ E' @& Y( w4 A
- Hello World
复制代码 8 P& r p" a8 _* `5 ~9 ^' Y4 T- O
虑一个简单的 print 语句。假如我们把 print 误拼为 Print,注意大写,这样 Python 会 引发 一个语法错误。# S4 F# V" l# C- Z4 w; V( R
9 t0 H' q2 z; n, x3 Y我们可以观察到有一个 SyntaxError 被引发,并且检测到的错误位置也被打印了出来。这是这个错误的 错误处理器 所做的工作。6 L5 J5 i" U( z
4 E' @+ N6 B: Y" X
try..except) {, C; a" V9 Y
我们尝试读取用户的一段输入。按 Ctrl-d,看一下会发生什么。
% p2 `- u* q: H) Z
e+ H3 p1 C% j5 w" E& s- >>> s = raw_input('Enter something --> ')
! T; V& P- w3 r1 H* D% D% O - Enter something --> Traceback (most recent call last):* @& u/ l! L! W$ S! E
- File "<stdin>", line 1, in ?
# b) j$ |' q! ]9 }. u - EOFError
复制代码 Python 引发了一个称为 EOFError 的错误,这个错误基本上意味着它发现一个不期望的 文件尾 (由 Ctrl-d 表示)+ w" m5 `; S9 Y2 c
$ \' w: z$ l, S) g" Z3 e! M6 H
接下来,我们将学习如何处理这样的错误。% Z" ^2 p, |! U( n1 d9 k- ^
! z3 }3 U, M/ q: h3 k$ l' I处理异常/ w% i* d7 X* |( }, q
我们可以使用 try..except 语句来处理异常。我们把通常的语句放在 try-块中,而把我们的错误处理语句放在 except-块中。
" ]! A" ~4 i6 ^, ?
3 k* M5 A0 @4 W1 ^5 E* J% d例 13.1 处理异常
5 `- @3 e8 c1 Y; Q+ P4 X. E- #!/usr/bin/python
" [& y) j# x' m* P% [# N% q; U0 K - # Filename: try_except.py
+ G7 W9 O' N1 _( _2 Y# J% [7 |6 O0 V
% I: G$ Y. H ]* A% t, p: M! e+ O- import sys
5 L# m7 i+ ~! e" P
% m |, d+ X: m! d+ p- try:- X# u" _/ g! V5 d
- s = raw_input('Enter something --> ')/ V/ u; W C' i9 g8 X) e( d
- except EOFError:
& b% }0 z- \, M1 ~ - print '\nWhy did you do an EOF on me?'
* R/ [+ D5 Q4 J( i; h5 x& o - sys.exit() # exit the program a' K" e8 T- j1 Z8 ?/ f; z
- except: T% Z% }6 Q# { d
- print '\nSome error/exception occurred.'4 }/ l- [* n: H' o3 m/ Z0 j4 P
- # here, we are not exiting the program5 y, K Z" d8 U( \" @
% c: Q, G3 t6 e5 {* V5 d- print 'Done'
复制代码 3 n7 R8 C c0 g
输出5 S( m$ T) S1 v6 R6 @
- $ python try_except.py
% J, g3 a1 L( o - Enter something -->
: ?- E5 `4 B; l: I! @ - Why did you do an EOF on me?5 c2 M! I- Q1 S# ~7 N& b$ ]+ E
- / y0 A* y6 }& Y$ [
- $ python try_except.py! G: Q0 V/ y5 b3 I) \
- Enter something --> Python is exceptional!
5 H, e# [' k, f+ D! D. G7 Z - Done
复制代码 ( Z; o4 R. p. A9 l
它如何工作
) h; Y& a5 a/ t T$ N6 G! h% {1 N6 P5 [
- }6 j+ @4 ?( G, s. f. V/ K我们把所有可能引发错误的语句放在 try 块中,然后在 except 从句/块中处理所有的错误和异常。 except 从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有给出错误或异常的名称,它会处理 所有的 错误和异常。对于每个 try 从句,至少都有一个相关联的 except 从句。
' ?5 I1 u/ S( {1 q9 ?/ p
, A( d7 {! [' ]0 d- ]0 }/ h* D如果某个错误或异常没有被处理,默认的 Python 处理器就会被调用。它会终止程序的运行,并且打印一个消息,我们已经看到了这样的处理。6 Y/ G6 H6 k+ c5 \
- y" E, W8 z6 J' {你还可以让 try..catch 块关联上一个 else 从句。当没有异常发生的时候,else 从句将被执行。, W7 G# a1 [8 J6 G+ }
5 l9 [1 K7 h5 f我们还可以得到异常对象,从而获取更多有个这个异常的信息。这会在下一个例子中说明。! V* \1 [+ a' J6 K
# ^* m2 J; |) y& ?) @5 x! T: F, K; L引发异常! n( A- V. w6 ]4 ?( u
你可以使用 raise 语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你可以引发的错误或异常应该分别是一个 Error 或 Exception 类的直接或间接导出类。
' p- y2 d7 p; {: t+ d2 O
2 E4 h- l8 @: y3 @. ~5 B- F如何引发异常
3 P4 H& o; Y# g( U4 B! |3 d9 a0 e例 13.2 如何引发异常4 i7 g1 [& X h
- #!/usr/bin/python: n% E a2 ~( S, w* a
- # Filename: raising.py/ W' N8 Y6 [# J
- 0 m! }/ Q$ ~) g* ?/ s% z8 X9 D' `
- class ShortInputException(Exception):
6 N3 v+ c6 g6 U' O/ x' V; F - '''A user-defined exception class.'''
8 c' q w$ y4 V8 \8 t- z' h - def __init__(self, length, atleast):
, u+ `9 |. T8 Z5 f: Q, } - Exception.__init__(self)
6 B L9 Q& ^ K2 z% b% p' d - self.length = length, u$ z/ X$ A8 Z) M1 ]
- self.atleast = atleast
7 f& H$ m2 x" D6 P - X% e: w9 o* c& J! F- ?0 J
- try:/ j. ^4 T2 Q5 a/ j: x+ P
- s = raw_input('Enter something --> ')
7 E' L' b7 B, K8 z - if len(s) < 3:
/ G" V& b) _7 M- u7 \* M2 @: k - raise ShortInputException(len(s), 3)! w+ Q2 S! o6 t g# C4 W
- # Other work can continue as usual here
[0 O' }. V( g2 l" k% w - except EOFError:: l7 |, O2 P) G6 q) W
- print '\nWhy did you do an EOF on me?'5 w1 r0 y( a) t4 Y( y, o% `' G t
- except ShortInputException, x:# S/ x7 N R( }0 S2 R- F+ C3 W
- print 'ShortInputException: The input was of length %d, \: x- N+ A( g; p1 t
- was expecting at least %d' % (x.length, x.atleast)
: a& }- m/ P0 \" ^: v1 F- [$ S - else:
8 M5 `8 w9 n) o - print 'No exception was raised.'
复制代码 ; O; T/ ], {( |/ b5 J# n
输出
x8 J4 N [* I& |' i; O- $ python raising.py" [$ M$ R. G3 ^$ v8 z
- Enter something -->
" j7 ~; s( f: x* p% ` - Why did you do an EOF on me?
7 a) K3 u6 s$ _& Y4 j, m8 F3 r, c
: s$ R9 V( O2 _- $ python raising.py4 U: f* A* |9 H4 m+ i
- Enter something --> ab
/ f% p% w. D/ `% U6 M - ShortInputException: The input was of length 2, was expecting at least 3; _. u" S, F. E1 L
% j' A- G6 }; G7 o4 u- $ python raising.py5 A$ |: d# G& a6 V' [1 a- z
- Enter something --> abc- `) s3 P4 I6 \4 ~
- No exception was raised.
复制代码 . R! K7 s0 C: o" ^6 A4 Z; ]6 ]
它如何工作
. b+ {! O7 h$ n( O# h3 ]
/ z8 V2 a/ u1 h- q3 G$ o6 s; ]: _这里,我们创建了我们自己的异常类型,其实我们可以使用任何预定义的异常/错误。这个新的异常类型是 ShortInputException 类。它有两个域—— length 是给定输入的长度,atleast 则是程序期望的最小长度。+ V4 z5 Y1 U; A1 D! y
' L& `9 @: {# o: u在 except 从句中,我们提供了错误类和用来表示错误/异常对象的变量。这与函数调用中的形参和实参概念类似。在这个特别的 except 从句中,我们使用异常对象的 length 和 atleast 域来为用户打印一个恰当的消息。. ~* d Z* r! r: G4 h
# Z, n! s f. I, \8 [try..finally
2 @0 L" n- o! y5 U z2 Z假如你在读一个文件的时候,希望在无论异常发生与否的情况下都关闭文件,该怎么做呢?这可以使用 finally 块来完成。注意,在一个 try 块下,你可以同时使用 except 从句和 finally 块。如果你要同时使用它们的话,需要把一个嵌入另外一个。
7 o+ a1 i$ y- v/ q
! d# p H1 h6 y( M- R使用finally
+ n0 n; P) `8 g, k, J例 13.3 使用finally
5 L5 h! N( I' ^7 e% e: w; c$ U' h/ [$ t# ^' a" ^8 b6 T
- #!/usr/bin/python
) _: ]/ h( _ @8 m* G( w8 G1 d3 s; c - # Filename: finally.py {, N" [6 M/ _
- 3 k0 u& G5 r4 R& {8 v+ r
- import time" ^4 B9 P( ?3 T. C: h- n
- : K: a5 ]# G3 J, I9 `
- try:0 W; b9 A: U+ B
- f = file('poem.txt')4 y) S( ?7 k% m4 a' s
- while True: # our usual file-reading idiom
0 b) Z1 a F$ V* U) x7 K! o - line = f.readline()
+ [- K$ H" h5 t+ \5 | - if len(line) == 0:' N, M# s6 J5 s3 y/ D4 i
- break m7 c" R6 G% b
- time.sleep(2)
* U% [9 N# m5 X- e7 [ - print line,
8 X& Z O7 O1 m1 h: \ - finally:
) h, p, K# J- } - f.close()
; z6 ^0 w3 m/ w$ z - print 'Cleaning up...closed the file'
复制代码
9 K2 |) h0 r$ ^5 w1 }, ^# e. P, K输出
0 s9 A' i0 j0 N- @- $ python finally.py
0 C' X+ O/ m" }. Y/ q$ O* m+ k - Programming is fun8 b5 Q" B7 X5 \4 X* m
- When the work is done: n! S4 K. r2 B( J
- Cleaning up...closed the file& |8 n9 u- x3 s! z% ^# k5 K% B
- Traceback (most recent call last):
k8 \: G* r% c7 Q$ Q - File "finally.py", line 12, in ?
b O2 L' \* o/ O2 l: K+ y$ j - time.sleep(2)
, x: N) x+ D; |$ l1 p/ O - KeyboardInterrupt
复制代码 # B9 X* k8 X4 j( c
它如何工作$ [8 ?, p* `: [% y8 G- m
% T( D- Y, F2 R H+ n我们进行通常的读文件工作,但是我有意在每打印一行之前用 time.sleep 方法暂停2秒钟。这样做的原因是让程序运行得慢一些(Python 由于其本质通常运行得很快)。在程序运行的时候,按 Ctrl-c 中断/取消程序。# W! C/ d0 X5 P6 _! z9 ?
& K$ Q) p8 k9 r; N% T
我们可以观察到 KeyboardInterrupt 异常被触发,程序退出。但是在程序退出之前,finally 从句仍然被执行,把文件关闭; E2 V3 F& Z- f1 ]- P# \9 k& ~: c0 J
' y/ [8 D) x4 T0 M
概括 `3 y1 n+ }/ @! g& M# o
我们已经讨论了 try..except 和 try..finally 语句的用法。我们还学习了如何创建我们自己的异常类型和如何引发异常。
. f! s# E; c T# b/ E4 r' k9 [- b G$ K y
接下来,我们将探索 Python 标准库。# A0 g C8 f: Q( x
) e, g* v) p' F: b |