摘要:盡量使用內置的異常處理語句來替換語句,比如語句,方法。以上是最簡單的重新拋出異常的做法,也是推薦的做法。除了包含所有的外還包含了,和三個異常。避免在語句塊中干一些沒意義的事情,捕獲異常也是需要成本的。
異常處理在任何一門編程語言里都是值得關注的一個話題,良好的異常處理可以讓你的程序更加健壯,清晰的錯誤信息更能幫助你快速修復問題。在Python中,和不部分高級語言一樣,使用了try/except/finally語句塊來處理異常,如果你有其他編程語言的經驗,實踐起來并不難。
異常處理語句 try...excpet...finally 實例代碼def div(a, b): try: print(a / b) except ZeroDivisionError: print("Error: b should not be 0 !!") except Exception as e: print("Unexpected Error: {}".format(e)) else: print("Run into else only when everything goes well") finally: print("Always run into finally block.") # tests div(2, 0) div(2, "bad type") div(1, 2) # Mutiple exception in one line try: print(a / b) except (ZeroDivisionError, TypeError) as e: print(e) # Except block is optional when there is finally try: open(database) finally: close(database) # catch all errors and log it try: do_work() except: # get detail from logging module logging.exception("Exception caught!") # get detail from sys.exc_info() method error_type, error_value, trace_back = sys.exc_info() print(error_value) raise總結如下
except語句不是必須的,finally語句也不是必須的,但是二者必須要有一個,否則就沒有try的意義了。
except語句可以有多個,Python會按except語句的順序依次匹配你指定的異常,如果異常已經處理就不會再進入后面的except語句。
except語句可以以元組形式同時指定多個異常,參見實例代碼。
except語句后面如果不指定異常類型,則默認捕獲所有異常,你可以通過logging或者sys模塊獲取當前異常。
如果要捕獲異常后要重復拋出,請使用raise,后面不要帶任何參數或信息。
不建議捕獲并拋出同一個異常,請考慮重構你的代碼。
不建議在不清楚邏輯的情況下捕獲所有異常,有可能你隱藏了很嚴重的問題。
盡量使用內置的異常處理語句來替換try/except語句,比如with語句,getattr()方法。
拋出異常 raise如果你需要自主拋出異常一個異常,可以使用raise關鍵字,等同于C#和Java中的throw,其語法規則如下。
raise NameError("bad name!")
raise關鍵字后面可以指定你要拋出的異常實例,一般來說拋出的異常越詳細越好,Python在exceptions模塊內建了很多的異常類型,通過使用dir()函數來查看exceptions中的異常類型,如下:
import exceptions print dir(exceptions) # ["ArithmeticError", "AssertionError"...]
當然你也可以查閱Python的文檔庫進行更詳細的了解。
https://docs.python.org/2.7/l...
自定義異常類型Python中自定義自己的異常類型非常簡單,只需要要從Exception類繼承即可(直接或間接):
class SomeCustomException(Exception): pass class AnotherException(SomeCustomException): pass
一般你在自定義異常類型時,需要考慮的問題應該是這個異常所應用的場景。如果內置異常已經包括了你需要的異常,建議考慮使用內置的異常類型。比如你希望在函數參數錯誤時拋出一個異常,你可能并不需要定義一個InvalidArgumentError,使用內置的ValueError即可。
經驗案例 傳遞異常 re-raise Exception捕捉到了異常,但是又想重新拋出它(傳遞異常),使用不帶參數的raise語句即可:
def f1(): print(1/0) def f2(): try: f1() except Exception as e: raise # don"t raise e !!! f2()
在Python2中,為了保持異常的完整信息,那么你捕獲后再次拋出時千萬不能在raise后面加上異常對象,否則你的trace信息就會從此處截斷。以上是最簡單的重新拋出異常的做法,也是推薦的做法。
還有一些技巧可以考慮,比如拋出異常前你希望對異常的信息進行更新。
def f2(): try: f1() except Exception as e: e.args += ("more info",) raise
如果你有興趣了解更多,建議閱讀這篇博客。
http://www.ianbicking.org/blo...
Python3對重復傳遞異常有所改進,你可以自己嘗試一下,不過建議還是遵循以上規則。
Exception 和 BaseException當我們要捕獲一個通用異常時,應該用Exception還是BaseException?我建議你還是看一下 官方文檔說明,這兩個異常到底有啥區別呢? 請看它們之間的繼承關系。
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration... +-- StandardError... +-- Warning...
從Exception的層級結構來看,BaseException是最基礎的異常類,Exception繼承了它。BaseException除了包含所有的Exception外還包含了SystemExit,KeyboardInterrupt和GeneratorExit三個異常。
由此看來你的程序在捕獲所有異常時更應該使用Exception而不是BaseException,因為被排除的三個異常屬于更高級別的異常,合理的做法應該是交給Python的解釋器處理。
except Exception as e和 except Exception, e代碼示例如下:
try: do_something() except NameError as e: # should pass except KeyError, e: # should not pass
在Python2的時代,你可以使用以上兩種寫法中的任意一種。在Python3中你只能使用第一種寫法,第二種寫法已經不再支持。第一個種寫法可讀性更好,而且為了程序的兼容性和后期移植的成本,請你果斷拋棄第二種寫法。
raise "Exception string"把字符串當成異常拋出看上去是一個非常簡潔的辦法,但其實是一個非常不好的習慣。
if is_work_done(): pass else: raise "Work is not done!" # not cool
上面的語句如果拋出異常,那么會是這樣的:
Traceback (most recent call last): File "/demo/exception_hanlding.py", line 48, inraise "Work is not done!" TypeError: exceptions must be old-style classes or derived from BaseException, not str
這在 Python2.4 以前是可以接受的做法,但是沒有指定異常類型有可能會讓下游沒辦法正確捕獲并處理這個異常,從而導致你的程序難以維護。簡單說,這種寫法是是封建時代的陋習,應該扔了。
使用內置的語法范式代替try/exceptPython 本身提供了很多的語法范式簡化了異常的處理,比如for語句就處理了的StopIteration異常,讓你很流暢地寫出一個循環。
with語句在打開文件后會自動調用finally并關閉文件。我們在寫 Python 代碼時應該盡量避免在遇到這種情況時還使用try/except/finally的思維來處理。
# should not try: f = open(a_file) do_something(f) finally: f.close() # should with open(a_file) as f: do_something(f)
再比如,當我們需要訪問一個不確定的屬性時,有可能你會寫出這樣的代碼:
try: test = Test() name = test.name # not sure if we can get its name except AttributeError: name = "default"
其實你可以使用更簡單的getattr()來達到你的目的。
name = getattr(test, "name", "default")最佳實踐
最佳實踐不限于編程語言,只是一些規則和填坑后的收獲。
只處理你知道的異常,避免捕獲所有異常然后吞掉它們。
拋出的異常應該說明原因,有時候你知道異常類型也猜不出所以然。
避免在catch語句塊中干一些沒意義的事情,捕獲異常也是需要成本的。
不要使用異常來控制流程,那樣你的程序會無比難懂和難維護。
如果有需要,切記使用finally來釋放資源。
如果有需要,請不要忘記在處理異常后做清理工作或者回滾操作。
關于作者:Python技術愛好者,目前從事測試開發相關工作,轉載請注明原文出處。
歡迎關注我的博客 https://betacat.online,你可以到我的公眾號中去當吃瓜群眾。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38259.html
摘要:總結判斷式的異常處理只能針對某一段代碼,對于不同的代碼段的相同類型的錯誤你需要寫重復的來進行處理。提示是基于文件句柄而存在的,因而只能在拋出異常后才可以執行異常類只能用來處理指定的異常情況,如果非指定異常則無法處理。 異常和錯誤 程序中難免出現錯誤,而錯誤分成兩種 1.語法錯誤(這種錯誤,根本過不了python解釋器的語法檢測,必須在程序執行前就改正) #語法錯誤示范一 if #語法...
小編寫這篇文章的一個主要目的,就是來給大家去做一個解答,解答的內容主要是Python常見的一些bug和異常問題,那么,遇到這些問題的時候,我們需要找到好辦法去進行處理。那么,小編這邊就給大家做了一個總結,總結常見的異常問題,大家好好閱讀哦。 異常處理介紹 在實際的開發中,我們經常遇到一些報錯的例子,在pycharm的顯示頁面下,當我們看到一串串的紅色的英文字母的時候,就是出現異常,這個時候...
摘要:但如果忽視異常輕則影響功能運行,重則導致系統崩潰,造成經濟損失。異常處理捕獲異常捕獲關鍵字與一致,都是使用。語句塊表示無論是否發生異常,語句塊代碼一定會被執行。 不少前端工程師看到這個標題可能會產生質問: 我js用得好好的,能后端能APP,為什么還要學習Python? 至少有下面兩個理由: 學習曲線。ES6之后的JavaScript(TypeScript)的在語法上和Python有很...
摘要:內存池機制提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。為了加速的執行效率,引入了一個內存池機制,用于管理對小塊內存的申請和釋放。 注:答案一般在網上都能夠找到。1.對if __name__ == main的理解陳述2.python是如何進行內存管理的?3.請寫出一段Python代碼實現刪除一個list里面的重復元素4.Python里面如何拷貝一個對象?...
摘要:使用中文替代中文中文編碼中文編碼中有以上兩種聲明字符串變量的方式,它們的主要區別是編碼格式的不同,其中,的編碼格式和文件聲明的編碼格式一致,而的編碼格式則是。 字符串是Python中最常用的數據類型,而且很多時候你會用到一些不屬于標準ASCII字符集的字符,這時候代碼就很可能拋出UnicodeDecodeError: ascii codec cant decode byte 0xc4 ...
閱讀 1574·2021-09-23 11:21
閱讀 2345·2021-09-07 10:13
閱讀 834·2021-09-02 10:19
閱讀 1125·2019-08-30 15:44
閱讀 1720·2019-08-30 13:18
閱讀 1913·2019-08-30 11:15
閱讀 1105·2019-08-29 17:17
閱讀 2017·2019-08-29 15:31