Python和很多其他語言一樣,支持異常處理。我們可以使用try-catch
類似的形式捕獲異常,處理異常,或者拋出異常。Python的異常命名慣例和Java語言有些不同, Java的異常一般以Exception
結尾,而Python的異常一般以Error
結尾。
常見異常
首先我們來看看常見異常,這些異常可能由于編碼錯誤或者其他原因導致。我們打開Python解釋器,然后瞎打一通代碼,應該就能看到不少異常了。
SyntaxError
系統錯誤最常見的原因就是編碼的縮進錯誤、或者缺少了分號、冒號等分隔符。例如下面的例子。
if 0>1
print()
File "<input>", line 1
if 0>1
^
SyntaxError: invalid syntax
NameError
這個異常通常是由于使用了未定義的名稱而引起的。
fuck
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'fuck' is not defined
ZeroDivisionError
這個異常是整數除零錯誤,一般在數學計算的時候才會出現。
1/0
Traceback (most recent call last):
File "<input>", line 1, in <module>
ZeroDivisionError: division by zero
ValueError
ValueError
異常一般在類型轉換失敗的時候出現。
int('3fuck')
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '3fuck'
處理異常
捕獲異常
Java等語言的使用try-catch
結構捕獲異常,在Python中也是類似的,不過捕獲異常使用except
關鍵字。在下面的例子中如果把第一行的fuck
注釋掉,就可以看到拋出了NameError
異常并由except
子句捕獲了。
fuck = 'fuck!!!'
try:
fuck
except NameError:
print('This is a NameError')
多個相似的異常可以使用同一個子句捕獲,這需要在except
子句中用括號包含多個異常類型。
try:
fuck
except (NameError, ValueError):
print('This is a NameError')
如果需要對不同的異常使用不同的異常子句捕獲,則可以列出多個異常子句。當拋出的異常是當前異常子句中異常的實例或者子類的實例時,都會匹配到當前子句。需要注意由于所有異常的父類是Excpetion
,所以Excpetion
類型的異常必須放到最后一個,避免其他異常子句無法執行。
try:
fuck
except (NameError, ValueError):
print('This is a NameError')
except SyntaxError:
print('This is a SystemError')
except Exception:
print('This is a RuntimeError')
最后一個異常子句的異常類型也可以省略,這樣就會捕獲所有其他未被捕獲的異常。
try:
fuck
except (NameError, ValueError):
print('This is a NameError')
except SyntaxError:
print('This is a SystemError')
except:
print('This is a RuntimeError')
如果需要獲取異常信息,可以使用as
關鍵字聲明異常變量,然后就可以在異常子句中使用了。
try:
fuck
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
清理資源
如果異常處理語句中包含了系統資源(文件、網絡連接、數據庫連接等),我們有義務在使用完畢后及時釋放這些資源。Python也提供了相應的機制。
釋放資源主要通過兩個子句來實現。第一個是else
子句,該子句僅當沒有拋出異常的時候才執行。如果有異常,這個字句就不會被執行。第二個子句是finally
子句,不管有沒有異常該語句都會執行。利用這兩個語句,我們就可以優雅的關閉資源了。
try:
raise MyError()
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
except MyError:
print('This is MyError')
else:
print('Else clause')
finally:
print('This is finally clause')
拋出異常
我們可以在合適的時候拋出異常,讓上級調用者決定如何處理異常。
下面的例子拋出了一個自定義異常。自定義異常是繼承了Exception
的類。定義之后使用raise
語句拋出異常。
class MyError(Exception):
pass
try:
raise MyError()
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
except MyError:
print('This is MyError')
如果在except
子句中無法處理異常,需要再次向上級拋出,直接使用raise
關鍵字即可。
try:
raise MyError()
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
except MyError:
print('This is MyError')
raise