python核心編程-錯誤與異常

本章主題:
什么是異常
Python中的異常
探測和處理異常
上下文管理
引發(fā)異常
斷言
標(biāo)準(zhǔn)異常
創(chuàng)建異常
相關(guān)模塊

什么是異常

  • 錯誤

從軟件方面來說吐根,錯誤是語法或是邏輯上的。語法錯誤只是軟件的結(jié)構(gòu)上有錯誤省有,導(dǎo)致不能被解釋器解釋或者編譯器無法編譯。這些錯誤必須在程序執(zhí)行前被糾正。
當(dāng)程序的語法正確之后潜沦,剩下的就是邏輯錯誤了盏阶。邏輯錯誤可能是由于不完整或是不合法的輸入所致晒奕,在其他情況下,還可能是邏輯無法生成名斟、計算脑慧、或是輸出結(jié)果需要的過程無法執(zhí)行。這些錯誤通常被稱為域錯誤和范圍錯誤砰盐。
當(dāng)Python檢測到一個錯誤時闷袒,解釋器會指出當(dāng)前流已經(jīng)無法繼續(xù)執(zhí)行下去。這個時候就出現(xiàn)異常岩梳。

  • 異常

對異常最好的描述是:它是因為程序出現(xiàn)了錯誤而在正衬抑瑁控制流以外采取的行為。這個行為又分為兩個階段:首先是引起異常發(fā)生的錯誤冀值,然后是檢測(和采取可能的措施)階段也物。

python中的異常
  • NameError :嘗試訪問一個未申明的變量

>>> foo
Traceback (innermost last):
  File "<stdin>",line 1, in ?
NameError: name 'foo' is not defined
#NameError 表示我們訪問了一個沒有初始化的變量。在Python解釋器的符號表沒有找到那個令人討厭的變量列疗,我們將在后面的兩章討論名稱空間滑蚯,現(xiàn)在大家可以認為它們是連接名字和對象的“地址簿”就可以了
#任何可訪問的變量必須在名稱空間里列出,訪問變量需要由解釋器進行搜索作彤,如果請求的名字沒有在任何名稱空間里找到膘魄,那么將會生成一個NameError異常
  • ZeroDivisionError : 除數(shù)為零
>>> 1/0
Traceback (inner last):
  File"<stdin>",line 1,in ?
ZeroDivisionError: integer division or modulo by zero

#任何數(shù)值被零除都會導(dǎo)致一個ZeroDivisionError異常
  • SyntaxError: Python 解釋器語法錯誤
>>> for 
    File "<string>", line 1
        for 
            ^
SyntaxError: invalid syntax
#SyntaxError 異常時唯一不是在運行時發(fā)生的異常。它代表Python
代碼中有一個不正確的結(jié)構(gòu)竭讳,在它改正之前程序是無法執(zhí)行的创葡。這些錯誤一般都是在編譯時發(fā)生,Python解釋器無法把你腳本轉(zhuǎn)化為python字節(jié)碼绢慢。也有可能是你導(dǎo)入了一個有缺陷的模塊灿渴。
  • IndexError : 請求的索引超出序列范圍
>>> alist = []
>>> alist[0]
Traceback (innermost last):
    File "<stdin>", line 1,in ?
IndexError: last index out of range
#IndexError 在你嘗試使用一個超出范圍的值索引序列引發(fā)洛波。
  • KeyError :請求一個不存在的字典的關(guān)鍵字
>>> aDict = {'host': 'earth','port':  80}
>>> print aDict['server']
Traceback (innermost last):
    File "<stdin>", line 1, in ?
KeyError: server

#映射對象,例如字典骚露,是依靠關(guān)鍵字(key)訪問數(shù)據(jù)的蹬挤,如果使用了錯誤的或者是不存在的鍵請求字典會引發(fā)一個KeyError異常。
  • IOError : 輸入/輸出錯誤
>>> f = open ("blah")
Traceback (innermost last):
    File "<stdin>",line 1, in ?
IOError: [Errno 2] No such file or directory: 'blah'

#類似嘗試打開一個不存在的磁盤文件一類的操作會引起一個操作系統(tǒng)輸入/輸出(I/O)錯誤棘幸。任何類型的I/O錯誤都會引發(fā)IOError異常
  • AttributeError : 嘗試訪問未知的對象屬性
>>> class myClass(object) :
...     pass
...
>>> myInst = myClass()
>>> myInst.bar = 'spam'
>>> myInst.bar
'spam'
>>> myInst.foo
Traceback (innermost last):
    File "<stdin>", line 1, in ?
AttributeError foo

#在這個例子里焰扳,我們在myInst.bar存儲了一個值,也就是實例myInst的bar屬性误续,屬性被定義后吨悍,我們可以使用梳洗的點屬性操作符訪問它,但如果是沒有定義屬性蹋嵌,例如我們訪問foo屬性育瓜,將導(dǎo)致一個AttributeError異常。
檢測和處理異常
異吃岳茫可以通過try語句來檢測躏仇。任何在try語句塊里的代碼都會被檢測,檢查有無異常發(fā)生腺办。
try語句有二種形式: try-except和try-finally 這兩個語句是互斥的焰手,也就是說你只能使用其中的一種。一個try語句可以對應(yīng)一個或者多個except子句菇晃,但只能對應(yīng)一個finally子句册倒,或者是一個try-except-finally復(fù)合語句。

try-except語句
try:
    try_suite #監(jiān)控這里的異常
except Exception[,reason]:
    except_suite #異常處理代碼

>>> try:
...    f = open ('blah','r')
... except IOError,e:
...    print 'could not open file:',e
...
cloud not open file: [Errno 2] No such file or directory
處理多個異常的except語句
#我們還可以在一個except子句里處理多個異常磺送。except語句在處理多個異常要求異常被放在一個元祖里:
except (Exception1,Exception2)[,reason]:
    suite_for_Exception1_and_Exception2

def safe_float(object):
    try:
        retval = float(object)
    except (ValueError,TypeError):
        retval = 'argument must be a number or numberic string'
    return retval
捕獲所有異常
#way1
#
try:
    :
except Exception, e:
     #error occurred,log 'e',etc.

#way2
#
try:
    :
except:
    #error occurred,etc

#關(guān)于捕獲所有異常驻子,你應(yīng)當(dāng)知道有些異常不是由錯誤條件引起的,它們是SystemExit和KeyboardInterupt估灿。
#SystemExit是由于當(dāng)前Python應(yīng)用程序需要退出
#KeyboardInterrupt是代表用戶按下了Ctrl+C崇呵,想要退出Python。在真正需要的時候馅袁,這些異常卻會被異常捕獲域慷。


異常被遷移到新式類(new-style class)啟用了一個新的“所有異常之母”,這個類叫做 BaseException汗销,異常的繼承結(jié)構(gòu)有了少許的調(diào)整犹褒,為了讓人們擺脫不得不除創(chuàng)建兩個處理器慣用法。

- BaseException
    | - KeyboardInterrupt
    | - SystemExit
    | - Exception
        | - (all other current bulit-in exception) 所有內(nèi)建異常

try:
    :
except Exception, e:
     #handle real errors

#如果你確實要捕獲所有異常弛针,那么你需要使用新的 BaseException:
try:
    :
except BaseException, e:
     #handle all errors

異常參數(shù)

異常也可以有參數(shù)叠骑,異常引發(fā)后它會被傳遞給異常處理器。當(dāng)異常被引發(fā)后參數(shù)是作為附加幫助信息傳遞給異常處理器的削茁。雖然異常原因是可選的宙枷,但標(biāo)準(zhǔn)內(nèi)建異常提供至少一個參數(shù)掉房,指示異常原因的一個字符串。
異常的參數(shù)可以在處理器里忽略慰丛,但是Python提供了保存這個值得語法卓囚。我們已經(jīng)在上邊接觸到相關(guān)內(nèi)容:要想訪問提供的異常原因,你必須保留一個變量來保存這個參數(shù)诅病。把這個參數(shù)放在except語句后哪亿,接在要處理的異常后面。except語句的這個語法可以被擴展為:

# single exception
except Exception[,reason]:
    suite_for_Exception_with_Argument

# multiple exception
except (Exception1,Exception2,...,ExceptionN)[,reason]:
    suite_for_Exception1_to_ExceptionN_with_Argument

#reason將會是一個包含來自導(dǎo)致異常的代碼的診斷信息的類實例。異常參數(shù)自身會組織一個元組,并存儲為類實例(異常類的實例)的屬性

無論reason只包含一個字符串或是由錯誤編號和字符串組成的元組是嗜,調(diào)用str(reason)總會返回一個良好可讀的錯誤原因存谎。不要忘記reason是一個類實例——這樣做你其實是調(diào)用類的特殊方法str()

信用卡交易系統(tǒng)(cardrun.py)
#!/usr/bin/env python

def safe_float(obj):
    'safe version if float()'
    try:
        retval = float(obj)
    except (ValueError,TypeError), diag:
        retval = str(diag)
    return retval

def main():
    'handle all the data processing'
    log = open('cardlog.txt', 'w')
    try:
        ccfile = open('carddata.txt', 'r')
    except IOError, e:
        log.write('no txns this month\n')
        log.close()
    return

    txns = ccfile.readlines()
    ccfile.close()
    total = 0.00
    log.write('account log:\n')

    for eachTxn in txns:
        result = safe_float(eachTxn)
        if isinstance(result,float):
            total += result
            log.write('data... processed\n')
        else:
            log.write('ignored: %s' %(result))

print '$%.2f (new balance)' % (total)
log.close()

if __name__ = '__main__':
    main()

else 子句

我們已經(jīng)看過else語句段配合其他python語句,比如條件和循環(huán)变勇。至于try-except語句段恤左,它的功能和你所見過的其他else沒有太多的不同: 在try范圍中沒有異常被檢測到時,執(zhí)行else子句

import 3rd_party_module
log = open('logfile','w')
try:
    3rd_party_module.function()
except:
    log.write("*** caught exception in module \n")
else:
    log.write("*** no exceptions caught\n")

log.close()
finally 子句

finally 子句是無論異常是否發(fā)生搀绣,是否捕捉都會執(zhí)行的一段代碼
下面是try-except-else-finally的語法實例:

try:
    A
except MyException:
    B
else:
    C
finally:
    D

#無論如何飞袋,你都可以有不止一個的except子句,但最少有一個except語句链患,而else和finally都是可選的巧鸭。無論異常發(fā)生在A、B或C都 將執(zhí)行finally塊麻捻。
通過try-finally來實現(xiàn)關(guān)閉文件而無論錯誤是否發(fā)生
#方式1
try:
    try:
        ccfile = open('carddata.txt')
        txns = ccfile.readlines()
    except IOError:
        log.write('no txns this month\n')
finally:
    ccfile.close()

#方式2
try:
    try:
        ccfile = open('carddata.txt')
        txns = ccfile.readlines()
    finally:
        ccfile.close()
except IOError:
    log.write('no txns this month\n')

上下文管理
  • with語句
    類似于 try-except-finally,with語句也是用來簡化代碼的纲仍,這與try-except和try-finally所想達到的目的前呼后應(yīng)。try-except和try-finally的一種特定的配合用法是保證共享資源的唯一分配贸毕,并在任務(wù)結(jié)束后釋放它郑叠。比如文件(數(shù)據(jù)、日志明棍、數(shù)據(jù)庫等等)乡革、線程資源、簡單同步摊腋、數(shù)據(jù)庫連接沸版,等等。
    然而兴蒸,with語句的目的在于從流程圖中把try视粮、except、finally關(guān)鍵字和資源分配釋放相關(guān)代碼統(tǒng)統(tǒng)去掉类咧,而不是像try-except-finally那樣僅僅簡化代碼使之易用
#with語法的基本語法如下:
with context_expr [as var]:
    with_suite

創(chuàng)建異常(myexc.py)
#!/usr/bin/env python
#

import os
import socket
import errno
import types
import tempfile

class NetworkError(IOError):
    pass

class FileError(IOError):
    pass

def updArgs(args,newarg=None):
    if isinstance(args,IOError):
        myargs = []
        myargs.extend([arg for arg in args])
    else:
        myargs = list(args) 

    if newarg:
        myargs.append(newarg)  

    return tuple(myarg)

def fileArgs(file, mode, args):
    if args[0] == errno.EACCES and 'access' in dir(os):
        perms = ''
        permd = { 'r': os.R_OK,'w': os.W_OK,'x': os.X_OK}
        pkeys = permd.keys()
        pkeys.sort()
        pkeys.reverse() 
        
        for eachPerm in 'rmx':
            if os.access(file, permd[eachPerm])
                perms += eachPerm
            else:
                perm += '-'
        if isinstance(args,IOError):
            myargs = []
            myargs.extend([arg for arg in args])
        else:
            myargs = list(args) 

        myargs[1] = " '%s' %s (perms: '%s')"% (mode, myargs[1], perms)
        myargs.append(args.filename)
    
    else:
        myargs = args
    
    return tuple(myargs)

def myconnect(sock, host, port):
    try:
        sock.connect((host, port))

    except socket.error, args:
        myargs = updArgs(args)
        if len(myargs) == 1:
            myargs = (error.ENXIO, myargs[0])
        
        raise NetworkError, updArgs(myargs, host + ': ' + str(port))
 
def myopen(file, mode='r'):
    try:
        fo = open(file, mode)
    except IOError, args:
        raise FileError, fileArgs(file, mode, args)
    
    return fo

def testfile():

    file = mktemp()
    f = open(file,'w')
    f.close()

    for eachTest in ((0, 'r'), (0100, 'r'),(0400, 'w'), (0500, 'w'))
        try:
            os.chmod(file, eachTest[0])
            f = open(file, eachTest[1])

        except FileError, args:
            print "%s: %s" % (args.__class__.__name__, args)
    
    else:
        print file, "opened ok... perm ignored"
        f.close()
  
    os.chmod(file, 0777)
    os.unlink(file)

def testnet():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    for eachHost in ('deli', 'www'):
        try:
            myconnect(s, 'deli', 8080)
        except NetworkError, args:
            print "%s: %s" % (args.__class__.__name__, args)

if __name__ == "__main__":
    testfile()
    testnet()







最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馒铃,一起剝皮案震驚了整個濱河市蟹腾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌区宇,老刑警劉巖娃殖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異议谷,居然都是意外死亡炉爆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門卧晓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芬首,“玉大人,你說我怎么就攤上這事逼裆∮羯裕” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵胜宇,是天一觀的道長耀怜。 經(jīng)常有香客問我,道長桐愉,這世上最難降的妖魔是什么财破? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮从诲,結(jié)果婚禮上左痢,老公的妹妹穿的比我還像新娘。我一直安慰自己系洛,他們只是感情好俊性,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碎罚,像睡著了一般磅废。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荆烈,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天拯勉,我揣著相機與錄音,去河邊找鬼憔购。 笑死宫峦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的玫鸟。 我是一名探鬼主播导绷,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屎飘!你這毒婦竟也來了妥曲?” 一聲冷哼從身側(cè)響起贾费,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎檐盟,沒想到半個月后褂萧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡葵萎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年导犹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羡忘。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡谎痢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卷雕,到底是詐尸還是另有隱情节猿,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布爽蝴,位于F島的核電站沐批,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蝎亚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一先馆、第九天 我趴在偏房一處隱蔽的房頂上張望发框。 院中可真熱鬧,春花似錦煤墙、人聲如沸梅惯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铣减。三九已至,卻和暖如春脚作,著一層夾襖步出監(jiān)牢的瞬間葫哗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工球涛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留劣针,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓亿扁,卻偏偏與公主長得像捺典,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子从祝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一襟己、簡介 Python最強大的結(jié)構(gòu)之一就是它的異常處理能力引谜,所有的標(biāo)準(zhǔn)異常都使用類來實現(xiàn),都是基類Exceptio...
    隨風(fēng)化作雨閱讀 3,073評論 0 1
  • Python異常處理 異常概念: 異常:就是不正常的情況擎浴,程序開發(fā)過程中錯誤和BUG都是補充正常的情況 異常發(fā)生的...
    youngkun閱讀 924評論 0 4
  • 1.什么是異常煌张? 異常即是一個事件,該事件會在程序執(zhí)行過程中發(fā)生退客,影響了程序的正常執(zhí)行骏融。一般情況下,Python無...
    歲月神偷_bde8閱讀 273評論 0 0
  • 王若智上小學(xué)二年級的時候萌狂。 一天档玻,他在放學(xué)回家的路上,看到一個賣過期方便面的男人茫藏,那個男人對王若智說:“小胖子误趴,快...
    1019d835891a閱讀 609評論 0 2
  • 開著? 聚焦务傲,如閃電凉当,光芒萬丈。 美麗如碎末的云朵售葡, 沉淀厚重碧薄藍天看杭。 念念不忘的褪色的記憶, 芥末黃般的魔幻挟伙,...
    李恩億的書屋閱讀 156評論 1 2