(69)Python異常處理與斷言

http://blog.csdn.net/pipisorry/article/details/21841883html

斷言

斷言是一句必須等價於布爾真的斷定;此外,發生異常也意味着表達式爲假.這些工做相似於 C 語言預處理器中 assert 宏,但在 Python 中它們在運行時構建(與之相對的是編譯期判別).
若是你剛剛接觸斷言這個概念,無妨.斷言能夠簡簡單單的想象爲 raise-if 語句(更準確的說是raise-if-not 語句).測試一個表達式,若是返回值是假,觸發異常.python

斷言語句等價於這樣的 Python 表達式,若是斷言成功不採起任何措施(相似語句),不然觸發AssertionError(斷言錯誤)的異常.assert 的語法以下:
assert expression[, arguments]數據庫

示例assert mode in ["train", "eval", "inference"],若是輸入的mode不在其中則觸發異常express

[Python中什麼時候使用斷言]編程

 

關於異常處理有必要麼的討論

最重要的問題是你在開發過程當中隱藏了bug,若是當時你沒加這個Try…Catch,恐怕你早就發現這個bug了,由於程序壓根就跑不下去。segmentfault

[try catch 對代碼運行的性能影響]socket

[你寫的Try...Catch真的有必要麼?]ide

 

 

異常處理

(含py2和py3的區別)函數

基本格式

Python 3
try:性能

   ...

except Exception as e:
    print(e)

不過lz推薦下面的格式:

 

import traceback
try:
...
except
:
print(traceback.format_exc())
input("hold on...")

直接調用print Exception, e獲得的結果就只有一行信息,只是異常的名字和說明而已。而這樣能夠輸出棧信息,ide中點擊就能夠到達錯誤位置,而且不會一閃而過。

異常

1)因此異常都從 BaseException繼承,並刪除了StardardError 。StandardError異常:在Python 2裏,StandardError是除了StopIterationGeneratorExitKeyboardInterruptSystemExit以外全部其餘內置異常的基類。在Python 3裏,StandardError已經被取消了;使用Exception替代。

Notes Python 2 Python 3
  =StandardError() =Exception()
  =StandardError(a, b, c) =Exception(a, b, c)

2)去除了異常類的序列行爲和.message屬性 

3)異常鏈,由於__context__在3.0a1版本中沒有實現 

  1. 相對於Python 2裏在異常類型後添加逗號,Python 3使用了一個新的關鍵字,as
  2. 關鍵字as也能夠用在一次捕獲多種類型異常的狀況下。
  3. 若是你捕獲到一個異常,可是並不在乎訪問異常對象自己,Python 2和Python 3的語法是同樣的。
  4. 相似地,若是你使用一個保險方法(fallback)來捕獲全部異常,Python 2和Python 3的語法是同樣的。

在導入模塊(或者其餘大多數狀況)的時候,你絕對不該該使用這種方法(指以上的fallback)。否則的話,程序可能會捕獲到像KeyboardInterrupt(若是用戶按Ctrl-C來中斷程序)這樣的異常,從而使調試變得更加困難。

觸發異常-raise語句

 

Python 3裏,拋出自定義異常的語法有細微的變化。

Notes Python 2 Python 3
raise MyException unchanged
raise MyException,'error message' raise MyException('error message')
raise MyException,'error message', a_traceback raise MyException('error message').with_traceback(a_traceback)
raise 'error message' unsupported

Note:

  1. 拋出不帶用戶自定義錯誤信息的異常,這種最簡單的形式下,語法沒有改變。
  2. 當你想要拋出一個帶用戶自定義錯誤信息的異常時,改變就顯而易見了。Python 2用一個逗號來分隔異常類和錯誤信息;Python 3把錯誤信息做爲參數傳遞給異常類。Python 2支持新舊兩種異常觸發語法,而Python 3只接受帶括號的的語法(否則會觸發SyntaxError)
  3. Python 2支持一種更加複雜的語法來拋出一個帶用戶自定義回溯(stack trace,堆棧追蹤)的異常。在Python 3裏你也能夠這樣作,可是語法徹底不一樣。
  4. 在Python 2裏,你能夠拋出一個不帶異常類的異常,僅僅只有一個異常信息。在Python 3裏,這種形式再也不被支持。2to3將會警告你它不能自動修復這種語法。

使用lambda匿名函數拋出異常

How can I write a lambda expression that's equivalent to:
def x():
    raise Exception()
The following is not allowed:
y = lambda : raise Exception()

 

lambda errmsg: exec('raise(Exception(errmsg))')

[Define a lambda expression that raises an Exception]

 

生成器的throw方法

在Python 2裏,生成器有一個throw()方法。調用a_generator.throw()會在生成器被暫停的時候拋出一個異常,而後返回由生成器函數獲取的下一個值。在Python 3裏,這種功能仍然可用,可是語法上有一點不一樣。

Notes Python 2 Python 3
a_generator.throw(MyException) no change
a_generator.throw(MyException,'error message') a_generator.throw(MyException('error message'))
a_generator.throw('error message') unsupported
  1. 最簡單的形式下,生成器拋出不帶用戶自定義錯誤信息的異常。這種狀況下,從Python 2到Python 3語法上沒有變化 。
  2. 若是生成器拋出一個帶用戶自定義錯誤信息的異常,你須要將這個錯誤信息字符串(error string)傳遞給異常類來以實例化它。
  3. Python 2還支持拋出只有異常信息的異常。Python 3不支持這種語法,而且2to3會顯示一個警告信息,告訴你須要手動地來修復這處代碼。

異常處理

Python 3中的異常處理也發生了一點變化。在Python 3中必須使用「as」關鍵字。

Python 2

try:
    let_us_cause_a_NameError
except NameError, err:
    print err, '--> our error message'

name 'let_us_cause_a_NameError' is not defined --> our error message

Python 3
try:
    let_us_cause_a_NameError
except NameError as err:
    print(err, '--> our error message')

name 'let_us_cause_a_NameError' is not defined --> our error message

 

except的一個例子:

考慮下面這個文件

import sys def bar(i): if i == 1: raise KeyError(1) def bad(): e = None try: bar(int(sys.argv[1])) except KeyError as e: print('key error') print(e) bad()

在python2中一切運做正常

$ python foo.py 1
key error 1 

可是在python3中事情變得一團糟

$ python3 foo.py 1

key error
Traceback (most recent call last):
  File "foo.py", line 19, in <module> bad() File "foo.py", line 17, in bad print(e) UnboundLocalError: local variable 'e' referenced before assignment

Note:問題出在,在Python3中,異常對象沒法在異常塊做用域外訪問。(緣由是在垃圾收集器運行且從內存中清理引用以前會在內存棧幀中保存一個引用週期)

解決此問題的方法之一是在異常塊做用域外圍護一個異常對象的引用,以使其可訪問。這裏是前例使用這一技術的一個版本,使得代碼對Python2和Python3都友好:

import sys
def bar(i): if i == 1: raise KeyError(1) def good(): exception = None try: bar(int(sys.argv[1])) except KeyError as e: exception = e print('key error') print(exception)

除0異常ZeroDivisionError

如今除以變量A=0都不會被try-except捕捉到了,會直接在運行時警告:

RuntimeWarning: divide by zero encountered in double_scalars

只有直接除以0纔會被try-except捕捉到

其它異常

x,y爲字典,若是x < y的不能比較,拋出TypeError異常。2.x版本是返回僞隨機布爾值的。

sys.exc_type, sys.exc_value, sys.exc_traceback

處理異常的時候,在sys模塊裏有三個你能夠訪問的變量:sys.exc_type,sys.exc_value,sys.exc_traceback。(實際上這些在Python 1的時代就有。)從Python 1.5開始,因爲新出的sys.exc_info,再也不推薦使用這三個變量了,這是一個包含全部以上三個元素的元組。在Python 3裏,這三個變量終於再也不存在了;這意味着,你必須使用sys.exc_info。

 

Notes Python 2 Python 3
  sys.exc_type sys.exc_info()[0]
  sys.exc_value sys.exc_info()[1]
  sys.exc_traceback sys.exc_info()[2]

皮皮blog

 

與異常處理相關的

[python上下文管理器ContextLib及with語句]

 

 

else配合 try except錯誤控制使用

在異常處理語句中,當try代碼塊沒有拋出任何的異常時,else語句塊會被執行到。
def my_to_int(str_param):
    try:
        print int(str_param)
    except ValueError:
        print 'cannot convert {} to a integer'.format(str_param)
    else:
        print 'convert {} to integer successfully'.format(str_param)
my_to_int("123")
my_to_int("me123")
convert 123 to integer successfully
cannot convert me123 to a integer

如打印日誌所示,在轉換成功未發生錯的的時候,else語句裏的邏輯會被執行,固然這個例子可能並無什麼太多的實際的用處,但大體能說明else在錯誤處理中的用處:簡化邏輯,避免使用一些標誌值就可以準確把握是否發生錯誤的狀況來作一些實際的操做(好比在保存數據的時候若是發生錯誤,在else語句塊中進行rollback的操做,而後緊接着還能加上finally語句完成一些清理操做。

Great Exceptations

Exceptions做爲一種控制結構,在處理數據庫、sockets、文件或者任何可能失敗的資源時很是經常使用。使用標準的 try 、except 結構寫數據庫操做時一般是類型這樣的方式。
try:
    # get API data
    data = db.find(id='foo') # may raise exception
    # manipulate the data
    db.add(data)
    # save it again
    db.commit() # may raise exception
except Exception:
    # log the failure
    db.rollback()
 
db.close()
你能發現這裏的問題嗎?這裏有兩種可能的異常會觸發相同的except模塊。這意味着查找數據失敗(或者爲查詢數據創建鏈接失敗)會引起回退操做。這絕對不是咱們想要的,由於在這個時間點上事務並無開始。一樣回退也不該該是數據庫鏈接失敗的正確響應,所以讓咱們將不一樣的狀況分開處理。


首先,咱們將處理查詢數據。
try:
    # get API data
    data = db.find(id='foo') # may raise exception
except Exception:
    # log the failure and bail out
    log.warn("Could not retrieve FOO")
    return


# manipulate the data
db.add(data)
如今數據檢索擁有本身的try-except,這樣當咱們沒有取得數據時,咱們能夠採起任何處理方式。沒有數據咱們的代碼不大可能再作有用的事,所以咱們將僅僅退出函數。除了退出你也能夠構造一個默認對象,從新進行檢索或者結束整個程序。
如今讓咱們將commit的代碼也單獨包起來,這樣它也能更優雅的進行錯誤處理。
try:
    db.commit() # may raise exception
except Exception:
    log.warn("Failure committing transaction, rolling back")
    db.rollback()
else:
    log.info("Saved the new FOO")
finally:
    db.close()
實際上,咱們已經增長了兩端代碼。首先,讓咱們看看else,當沒有異常發生時會執行這裏的代碼。在咱們的例子中,這裏只是將事務成功的信息寫入日誌,可是你能夠按照須要進行更多有趣的操做。一種可能的應用是啓動後臺任務或者通知。
很明顯finally 子句在這裏的做用是保證db.close() 老是可以運行。回顧一下,咱們能夠看到全部和數據存儲相關的代碼最終都在相同的縮進級別中造成了漂亮的邏輯分組。之後須要進行代碼維護時,將很直觀的看出這幾行代碼都是用於完成 commit操做的。

皮皮blog

 

 

附錄

常見的python異常類型

[Python異常編程技巧]

from:http://blog.csdn.net/pipisorry/article/details/21841883

相關文章
相關標籤/搜索