[1] Python異常處理
1. 概述
在本文中我會介紹關於在Python中如何處理各種錯誤異常。首先我們來看一下我們在上一篇中擬定的學習計劃,加粗體代表我們已經介紹的內容,斜體代表新增內容。
異常處理
檔案的讀寫
正則表示式
操作檔案和目錄
深複製和淺複製
面向物件的程式設計
變數(擴充套件介紹)
二進位制、八進位制和十六進位制(包括ASCII)
迭代、生成和遞迴
高階函式map
匿名函式lambda
影象處理(運用numpy)
2. 異常型別
異常有各種各樣,比如我們輸入
a
=
1
/
0
肯定是會報錯的,0不能作為除數,還比如:
a
=
[
0
,
1
,
2
,
3
,
4
,
]
a
[
100
]
也肯定會報錯,因為這個數列壓根就沒有第100位。
報錯的時候,我們通常會看到PyCharm下面執行區內紅紅的一堆字提示錯誤。
我們能見到的異常型別有各種各樣,
BaseException
+—— SystemExit
+—— KeyboardInterrupt
+—— GeneratorExit
+—— Exception
+—— StopIteration
+—— StopAsyncIteration
+—— ArithmeticError
| +—— FloatingPointError
| +—— OverflowError
| +—— ZeroDivisionError
+—— AssertionError
+—— AttributeError
+—— BufferError
+—— EOFError
+—— ImportError
| +—— ModuleNotFoundError
+—— 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
這些都是在官網文件上覆制貼上下來的,這裡面的比如NameError,指的是我們用了沒有定義的變數名,FileNotFoundError指的是要讀取的檔案不存在,ZeroDivisionError指的是我們除以了一個零。大家可以點選下面的連結來了解各種錯誤異常。
3. 處理異常
如果我們的程式碼有錯,程式就會在遇見第一個錯誤時報錯並停止執行,為了讓程式能夠平穩執行,不被錯誤所打擾,這裡我們需要知道如何處理:
try
:
# Your code
except
:
# What to do with the exception/error
我們需要在我們可能產生錯誤的程式碼外面套上try…except語句。try下面直接寫上我們原先的程式碼,except下面寫上我們如果遇到程式異常後該怎麼做,這樣的話我們程式就能遇到錯誤後依舊平穩執行。
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
break
except
:
(
‘That was no valid number。’
)
我們執行這段程式碼,我們可以看到如果我們輸入不是整數的話,就會輸出except下面的那句話,但是程式並沒有“異常終止”,如果我們輸入的是整數的話,程式就會安靜地執行結束。
可以看到,錯誤產生時while迴圈並未被break打斷,可以得知
異常被捕捉到後馬上就會忽略之後的內容,並且直接跳至except。
當然我們可以更清晰一點:
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
break
except
ValueError
:
(
‘That was no valid number。’
)
因為int後面的不能轉換為整數時會歸為ValueError。如果我們不知道是何種異常時,我們操作方法可以是:
只寫except,
執行沒有try…except的語句,故意輸入錯誤,看紅字顯示是什麼再回來改
用Exception代替所有可能性,如下
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
break
except
Exception
:
(
‘That was no valid number。’
)
當然,你也可以用BaseException,這裡要知道所有的基本錯誤都歸於BaseException下,且絕大部分錯誤是歸於Exception下的。
4. 多種異常
當然,我們的程式碼有時候會因各種原因碰見多種異常,比如
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
break
except
Exception
:
(
‘Some error occurred。’
)
如果使用者輸入非整數,就會跑except去,如果使用者輸入是0,0不能做除數,也會跑except去。這是我們可以這樣:
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
break
except
ValueError
:
(
‘That was no valid number。’
)
except
ZeroDivisionError
:
(
‘100 / 0 is invalid。’
)
這樣我們就能在執行時區分到底錯在哪裡了。當然由於try發現異常後會去找
第一個
能處理此異常的except,在這裡兩個except不相關,能交換位置。
而下面的程式碼:
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
break
except
Exception
:
(
‘Exception!’
)
except
ValueError
:
(
‘That was no valid number。’
)
except
ZeroDivisionError
:
(
‘100 / 0 is invalid。’
)
這裡它只會看第一個except,發現錯誤後永遠只會輸出Exception,原因是Exception包含了ValueError和ZeroDivisionError,try發現異常後看到第一句except能處理,就把異常交給第一個except,自動忽略後面的。
我們還可以如此處理多種異常:
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
break
except
(
ZeroDivisionError
,
ValueError
):
(
‘Exception!’
)
用括號括起來,裡面能寫幾個寫幾個,這樣的話我們如果遇見括號裡面任意一種異常,就能執行此except。
5. 異常所攜帶的資訊
通常異常中會帶有資訊,我們可以賦予異常一個變數名以輸出具體資訊:
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
break
except
(
ZeroDivisionError
,
ValueError
)
as
e
:
(
e
)
當然不一定非得命名為e,如果我們輸入0,則會輸出:
division by zero
而如果我們輸入非整數,而是其他字元的話,比如我輸入了apple,則會輸出:
invalid literal for int() with base 10: ‘apple’
這些都是這寫異常所攜帶的資訊。
6. finally和else語句
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
break
except
(
ZeroDivisionError
,
ValueError
)
as
e
:
(
e
)
finally
:
(
‘Goodbye!’
)
也就是說不管有沒有錯,在執行完上述的程式碼後,一定會執行finally內部的程式碼。如果我們輸入的是0或者非整數,會輸出錯誤資訊後帶著輸出Goodbye然後繼續迴圈會try,如果我們輸入正確,執行沒有錯,while True被break順利終止了,還是會繼續finally內部的程式碼,輸出Goodbye。
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
(
100
/
x
)
except
(
ZeroDivisionError
,
ValueError
)
as
e
:
(
e
)
else
:
(
‘Goodbye!’
)
break
else語句只有在try下面沒有錯的情況下才會執行,注意我把break移到else下面了,我們可以把它看作是try內部內容的延伸。
7. raise語句
當然,我們在自己寫碼的時候,也會需要在某些場合
輸出異常
。比如我們認為負整數不是整數,那麼輸入後,我們可以手動輸出此異常。
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
if
x
<
0
:
raise
ValueError
break
except
ValueError
as
e
:
(
e
)
但是由於這個ValueError是我們自己輸出的,這麼寫我們並不會看到其攜帶資訊,我們可以這麼做讓其攜帶自定義資訊:
while
True
:
try
:
x
=
int
(
input
(
‘Please enter a number: ’
))
if
x
<
0
:
raise
ValueError
(
‘Negative number is not allowed’
)
break
except
ValueError
as
e
:
(
e
)
輸出測試:
Please enter a number: y
invalid literal for int() with base 10: ‘y’
Please enter a number: -9
Negative number is not allowed
Please enter a number: 0
輸入0,沒有錯誤,程式順利結束。