如何获取exception的target异常_三个好习惯,帮你写好Python里的异常处理
文:pigpei 源:公眾號pigpei
如果你用 Python 編程,那么你就無法避開異常,因為異常在這門語言里無處不在。打個比方,當你在腳本執行時按 ctrl+c 退出,解釋器就會產生一個 KeyboardInterrupt 異常。而 KeyError、 ValueError、 TypeError 等更是日常編程里隨處可見的老朋友。
異常處理工作由“捕獲”和“拋出”兩部分組成。“捕獲”指的是使用 try...except 包裹特定語句,妥當的完成錯誤流程處理。而恰當的使用 raise 主動“拋出”異常,更是優雅代碼里必不可少的組成部分。
在這篇文章里,我會分享與異常處理相關的 3 個好習慣。繼續閱讀前,我希望你已經了解了下面這些知識點:
- 異常的基本語法與用法(建議閱讀官方文檔 “Errors and Exceptions”)
- 為什么要使用異常代替錯誤返回(建議閱讀《讓函數返回結果的技巧》)
- 為什么在寫 Python 時鼓勵使用異常 (建議閱讀 “Write Cleaner Python: Use Exceptions”)
三個好習慣
1. 只做最精確的異常捕獲
假如你不夠了解異常機制,就難免會對它有一種天然恐懼感。你可能會覺得:異常是一種不好的東西,好的程序就應該捕獲所有的異常,讓一切都平平穩穩的運行。而抱著這種想法寫出的代碼,里面通常會出現大段含糊的異常捕獲邏輯。
讓我們用一段可執行腳本作為樣例:
# -*- coding: utf-8 -*-import requestsimport redef save_website_title(url, filename): """獲取某個地址的網頁標題,然后將其寫入到文件中 :returns: 如果成功保存,返回 True,否則打印錯誤,返回 False """ try: resp = requests.get(url) obj = re.search(r'(.*)', resp.text) if not obj: print('save failed: title tag not found in page content') return False title = obj.grop(1) with open(filename, 'w') as fp: fp.write(title) return True except Exception: print(f'save failed: unable to save title of {url} to {filename}') return Falsedef main(): save_website_title('https://www.qq.com', 'qq_title.txt')if __name__ == '__main__': main()腳本里的 save_website_title 函數做了好幾件事情。它首先通過網絡獲取網頁內容,然后利用正則匹配出標題,最后將標題寫在本地文件里。而這里有兩個步驟很容易出錯:網絡請求 與 本地文件操作。所以在代碼里,我們用一個大大的 try...except 語句塊,將這幾個步驟都包裹了起來。安全第一 ?。
那么,這段看上去簡潔易懂的代碼,里面藏著什么問題呢?
如果你旁邊剛好有一臺安裝了 Python 的電腦,那么你可以試著跑一遍上面的腳本。你會發現,上面的代碼是不能成功執行的。而且你還會發現,無論你如何修改網址和目標文件的值,程序仍然會報錯 “save failed: unable to...”。為什么呢?
問題就藏在這個碩大無比的 try...except 語句塊里。假如你把眼睛貼近屏幕,非常仔細的檢查這段代碼。你會發現在編寫函數時,我犯了一個小錯誤,我把獲取正則匹配串的方法錯打成了 obj.grop(1),少了一個 'u'( obj.group(1))。
但正是因為那個過于龐大、含糊的異常捕獲,這個由打錯方法名導致的原本該被拋出的 AttibuteError 卻被吞噬了。從而給我們的 debug 過程增加了不必要的麻煩。
異常捕獲的目的,不是去捕獲盡可能多的異常。假如我們從一開始就堅持:只做最精準的異常捕獲。那么這樣的問題就根本不會發生,精準捕獲包括:
- 永遠只捕獲那些可能會拋出異常的語句塊
- 盡量只捕獲精確的異常類型,而不是模糊的 Exception
依照這個原則,我們的樣例應該被改成這樣:
from requests.exceptions import RequestExceptiondef save_website_title(url, filename): try: resp = requests.get(url) except RequestException as e: print(f'save failed: unable to get page content: {e}') return False # 這段正則操作本身就是不應該拋出異常的,所以我們沒必要使用 try 語句塊 # 假如 group 被誤打成了 grop 也沒關系,程序馬上就會通過 AttributeError 來 # 告訴我們。 obj = re.search(r'(.*)', resp.text) if not obj: print('save failed: title tag not found in page content') return False title = obj.group(1) try: with open(filename, 'w') as fp: fp.write(title) except IOError as e: print(f'save failed: unable to write to file {filename}: {e}') return False else: return True2. 別讓異常破壞抽象一致性
大約四五年前,當時的我正在開發某移動應用的后端 API 項目。如果你也有過開發后端 API 的經驗,那么你一定知道,這樣的系統都需要制定一套“API 錯誤碼規范”,來為客戶端處理調用錯誤時提供方便。
一個錯誤碼返回大概長這個樣子:
// HTTP Status Code: 400// Content-Type: application/json{ "code": "UNABLE_TO_UPVOTE_YOUR_OWN_REPLY總結
以上是生活随笔為你收集整理的如何获取exception的target异常_三个好习惯,帮你写好Python里的异常处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WEB编程学习之Wordpress发送邮
- 下一篇: [4] ADB 应用管理