本片筆記學習自:Write Cleaner Python: Use Exceptions
當我說使用異常,我并不是說在你的包中創建一些異常類,然后在每個可能的地方都拋出異常。我想說盡量利用Python內建的異常。事實上,你的代碼到處都有異常機制在工作。
- for循環是怎么工作的?
words = ['exceptions', 'are', 'useful']
for word in words:
print(word)
for循環怎么知道什么時候結束呢?在迭代器結束的時候,迭代器會拋出StopIteration異常,
- 為什么使用異常?
for循環顯然可以不用異常來實現,那為什么要用異常?因為python所采用的檢查錯誤的哲學。
如果不使用異常,我們在事情之前首先要檢查條件是否都符合再執行。如果你不仔細檢查所有可能的錯誤,災難就發生了。考慮以下代碼:
def print_object(some_object):
# Check if the object is printable...
if isinstance(some_object, str):
print(some_object)
elif isinstance(some_object, dict):
print(some_object)
elif isinstance(some_object, list):
print(some_object)
# 97 elifs later...
else:
print("unprintable object")
想要提前預料所有錯誤狀況注定要失敗。
如果使用異常,我們可以寫成下面的代碼:
def print_object(some_object):
# Check if the object is printable...
try:
printable = str(some_object)
print(printable)
except TypeError:
print("unprintable object")
- 更多使用情況
else的使用:在沒有異常拋出的時候執行。下面的代碼同時也修正了上面代碼可能存在的一個bug,就是可能是print導致的異常而不是str強制類型轉化導致的。else里面也經常用來放一些收尾工作的代碼,比如關閉數據庫等等。
def print_object(some_object):
# Check if the object is printable...
try:
printable = str(some_object)
except TypeError:
print("unprintable object")
else:
print(printable)
raise的使用:通常raise用來拋出異常,但是在我們處理異常的時候,我們也可以做一些事情,然后繼續把原來的異常繼續拋上去,這讓上層應用可以知道異常的來源,而如果我們在處理異常的時候重新拋出一個異常,這就會讓上層應用不知道真正的異常來自哪里。
上面兩種處理異常的情況,也就是if提前判斷和使用異常,這兩個方法分別是Look Before You Leap (LBYL) and Easier to Ask for Forgiveness than Permission,后者是盡管去做事情,如果出現異常,處理它。
- 異常的代價
異常也損失一些性能,但是在python中代價很小。