更多課程 選擇中心

Python培訓
美國上市教育機構

400-111-8989

Python培訓

穩住,別慌!這就送你Python中的異常處理寶典!

  • 發布:Python培訓
  • 來源: 哎媽呀Bug
  • 時間:2018-09-05 15:48

Python中的異常處理寶典

在我們進行程序語言編寫的過程中,我們百分之百追求完美,但避免不了異常,在python中也是一樣的,經驗人士可能已經習慣了異常的出現與修復,但對于一個新人來說,還是有些忐忑的,今天就送你Python中的異常處理寶典,穩住,我們能贏!

異常處理在任何一門編程語言里都是值得關注的一個話題,良好的異常處理可以讓你的程序更加健壯,清晰的錯誤信息更能幫助你快速修復問題。在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

# ['ArithmeticError', 'AssertionError'.....]

print dir(exceptions)

自定義異常類型

Python中也可以自定義自己的特殊類型的異常,只需要要從Exception類繼承(直接或間接)即可:

class SomeCustomException(Exception):

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

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, in <module>

raise "Work is not done!"

TypeError: exceptions must be old-style classes or derived from BaseException, not str

這在Python2.4以前是可以接受的做法,但是沒有指定異常類型有可能會讓下游沒辦法正確捕獲并處理這個異常,從而導致你的程序掛掉。簡單說,這種寫法是是封建時代的陋習,應該扔了。

使用內置的語法范式代替try/except

Python本身提供了很多的語法范式簡化了異常的處理,比如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()

ame = test.name # not sure if we can get its name

except AttributeError:

ame = 'default'

其實你可以使用更簡單的getattr()來達到你的目的。

ame = getattr(test, 'name', 'default')

最佳實踐

最佳實踐不限于編程語言,只是一些規則和填坑后的收獲。

只處理你知道的異常,避免捕獲所有異常然后吞掉它們。

拋出的異常應該說明原因,有時候你知道異常類型也猜不出所以然的。

避免在catch語句塊中干一些沒意義的事情。

不要使用異常來控制流程,那樣你的程序會無比難懂和難維護。

如果有需要,切記使用finally來釋放資源。

如果有需要,請不要忘記在處理異常后做清理工作或者回滾操作。

恭喜你拿走了這份Python中的異常處理寶典,相信這些你真的可以穩住,我們也真的可以贏了!異常情況就像是我們要打敗的敵人一樣, 遇到他們切記別慌,心態很重要!如果你還想了解更多關于Python的知識點,歡迎到達內Python培訓機構獲取吧!

免責聲明:內容和圖片源自網絡,版權歸原作者所有,如有侵犯您的原創版權請告知,我們將盡快刪除相關內容。

預約申請免費試聽課

填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

上一篇:Python中五種下劃線如此多嬌,竟如此容易混淆!
下一篇:熟悉Python10大集成開發環境和代碼編輯器,讓編程充滿樂趣!

如何運用Python編程處理大數據?用Python編程處理大數據的技巧是什么?

Python面向對象編程的知識點都在這了!

Python的高級特征及用法(部分)

聽說這些Python知識,很少有人知道!

選擇城市和中心
黑龍江省

吉林省

河北省

湖南省

貴州省

云南省

廣西省

海南省

4438全国大成网人网站