Python學(xué)習(xí)筆記八2:異常

@[toc]
??編寫計算機(jī)程序時洋满,通常能夠區(qū)分正常和異常情況。異常事件可能是錯誤,也可能是通常不會發(fā)生的事情胀茵。為處理這些異常事件吐句,Python提供功能強(qiáng)大的異常處理機(jī)制。

一店读、異常是什么

??Python使用異常對象來表示異常狀態(tài)嗦枢,并在遇到錯誤時引發(fā)異常。異常對象未被處理(或捕獲)時屯断,程序?qū)⒔K止并顯示一條錯誤消息(traceback)文虏。

>>> 1/0
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    1/0
ZeroDivisionError: division by zero

??事實上,每個異常都是某個類(這里是ZeroDivisionError)的實例殖演。你能以各種方式引發(fā)和捕獲這些實例氧秘,從而逮住錯誤并采取措施,而不是讓程序失敗

二趴久、讓事情沿你指定的軌道出錯

??正如你看到的丸相,出現(xiàn)問題時,將自動引發(fā)異常彼棍。先來看看如何自主地引發(fā)異常灭忠,還有如何創(chuàng)建異常,然后再學(xué)習(xí)如何處理這些異常座硕。

1. raise語句

??Python使用raise語句拋出一個指定異常弛作。要引發(fā)異常,可使用raise語句华匾,并將一個類(必須是Exception的子類)或?qū)嵗鳛閰?shù)映琳。將類作為參數(shù)時,將自動創(chuàng)建一個實例。下面的示例使用的是內(nèi)置異常類Exception

>>> raise Exception
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    raise Exception
Exception

??這里引發(fā)的是通用異常萨西,并沒有指出出現(xiàn)了什么錯誤有鹿。

>>> raise Exception('hyperdrive overload')
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    raise Exception('hyperdrive overload')
Exception: hyperdrive overload

??這里添加了錯誤信息hyperdrive overload
??在很多內(nèi)置的異常類原杂,表描述了最重要的幾個印颤。
<center>一些內(nèi)置的異常類</center>

類名 描述
Exception 幾乎所有的異常類都是從它派生而來的
AttributeError 引用屬性或給它賦值失敗時引發(fā)
OSError 操作系統(tǒng)不能執(zhí)行指定的任務(wù)(如打開文件)時引發(fā),有多個子類
IndexError 使用序列中不存在的索引時引發(fā)穿肄,為LookupError的子類
KeyError 使用映射中不存在的鍵時引發(fā)年局,為LookupError的子類
NameError 找不到名稱(變量)時引發(fā)
SyntaxError 代碼不正確時引發(fā)
TypeError 將內(nèi)置操作或函數(shù)用于類型不正確的對象時引發(fā)
ValueError 將內(nèi)置操作或函數(shù)用于這樣的對象時引發(fā):其類型正確但包含的值不合適
ZeroDivisionError 在除法或求模運算的第二個參數(shù)為零時引發(fā)

2. 自定義的異常類

??我們可以像創(chuàng)建其他類一樣,但務(wù)必直接或間接地繼承Exception(這意味著從任何內(nèi)置異常類派生都可以)咸产。因此矢否,自定義異常類的代碼類似于下面這樣:

class SomeCustomException(Exception): pass

??因為錯誤就是類,捕獲一個錯誤就是捕獲一個該類的實例脑溢,因此錯誤并不是憑空產(chǎn)生的僵朗,而是由一些不合理的部分導(dǎo)致的。Python的內(nèi)置函數(shù)會拋出很多類型的錯誤屑彻,我們自己編寫的函數(shù)也可以拋出錯誤验庙。如果要拋出錯誤,那么可以根據(jù)需要定義一個錯誤的類社牲,選擇好繼承關(guān)系粪薛,然后用raise語句拋出一個錯誤的實例。
??例如:

class MyError(Exception):
    def __init__(self):
        pass
    def __str__(self):
        return 'this is self define error'
def my_error_test():
    try:
        raise MyError()
    except MyError as e:
        print('exception info:',e)
my_error_test()

??執(zhí)行結(jié)果如下:

exception info:this is self define error

??程序正確地執(zhí)行了自定義的異常搏恤。

三违寿、捕獲異常

??異常比較有趣的地方是可對其進(jìn)行處理,通常稱之為捕獲異常熟空。為此藤巢,可使用try/except語句try/except語句用來檢測try語句中的錯誤息罗,從而讓except語句捕獲異常信息并處理掂咒。假設(shè)你創(chuàng)建了一個程序,讓用戶輸入兩個數(shù)迈喉,再將它們相除俏扩,如下所示:

>>> x = int(input('Enter the first number:'))
>>> y = int(input('Enter the second number'))
>>> print(x / y)

??如果第二個數(shù)字為零的話,就會報錯弊添。為了捕獲這種異常并對錯誤進(jìn)行處理录淡,可像下面這樣重寫程序。

try:
    x = int(input('Enter the first number:'))
    y = int(input('Enter the second number:'))
    print(x / y)
except ZeroDivisionError:
    print("第二個數(shù)字不能為0")

??try的工作原理是油坝,開始一個try語句后嫉戚,Python就在當(dāng)前程序的上下文中做標(biāo)記刨裆,當(dāng)出現(xiàn)異常時就可以回到做標(biāo)記的地方。首先執(zhí)行try語句彬檀,接下來發(fā)生什么依賴于執(zhí)行時是否出現(xiàn)異常帆啃。
??如果try后的語句執(zhí)行時發(fā)生異常,程序就跳回try并執(zhí)行except子句窍帝。異常處理完畢努潘,控制流就可以通過整個try語句了(除非在處理異常時又引發(fā)新異常)。
??注意:異常從函數(shù)向外傳播到調(diào)用函數(shù)的地方坤学。如果在這里也沒有被捕獲疯坤,異常將向程序的最頂層傳播。這意味著你可使用try/except來捕獲他人所編寫函數(shù)引發(fā)的異常深浮。詳見第4小節(jié)压怠。

1. 不用提供參數(shù)

??捕獲異常后,如果要重新引發(fā)它(即繼續(xù)向上傳播)飞苇,可調(diào)用raise且不提供任何參數(shù)(也可顯式地提供捕獲到的異常菌瘫,參見(4))。

>>> raise
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    raise
RuntimeError: No active exception to reraise

??為說明這很有用布卡,來看一個能夠抑制異常ZeroDivisionError的計算器類雨让。如果啟用了這種功能,計算器將打印一條錯誤消息忿等,而不讓異常繼續(xù)傳播宫患。在與用戶交互的會話中使用這個計算器時,抑制異常很有用这弧;但在程序內(nèi)部使用時,引發(fā)異常是更佳的選擇(此時應(yīng)關(guān)閉抑制功能)虚汛。
??下面來看一個類的代碼:

class MuffledCalculator:
    muffled = False
    def calc(self, expr):
        try:
            return eval(expr)   
        except ZeroDivisionError:
            if self.muffled:
                print('Division by zero is illegal')
            else:
                raise
# eval()將字符串str當(dāng)成有效的表達(dá)式來求值并返回計算結(jié)果

??注意:發(fā)生除零行為時匾浪,如果啟用了抑制功能,方法calc將(隱式地)返回None卷哩。換而言之蛋辈,如果啟用了抑制功能,就不應(yīng)依賴返回值将谊。
??下面的示例演示了這個類的用法(包括啟用和關(guān)閉了抑制功能的情形):

>>> calculator = MuffledCalculator()
>>> calculator.calc('10/2')
5.0
>>> calculator.calc('10/0') #關(guān)閉了抑制功能
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    calculator.calc('10/0')
  File "<pyshell#15>", line 5, in calc
    return eval(expr)
  File "<string>", line 1, in <module>
ZeroDivisionError: division by zero
>>> calculator.muffled = True   #開啟了抑制功能
>>> calculator.calc('10/0')
Division by zero is illegal

??如你所見冷溶,關(guān)閉抑制功能時,捕獲了異常ZeroDivisionError尊浓,但繼續(xù)向上傳播它逞频。
??如果無法處理異常,在except子句中使用不帶參數(shù)的raise通常是不錯的選擇栋齿,但有時你可能想引發(fā)別的異常苗胀。在這種情況下襟诸,導(dǎo)致進(jìn)入except子句的異常將被作為異常上下文存儲起來,并出現(xiàn)在最終的錯誤消息中基协。

>>> try:
    1/0
except ZeroDivisionError:
    raise ValueError
Traceback (most recent call last):
  File "<pyshell#28>", line 2, in <module>
    1/0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<pyshell#28>", line 4, in <module>
    raise ValueError

??你可使用raise…from…語句來提供自己的異常上下文歌亲,也可使用None來禁用上下文。

>>> try:
    1/0
except ZeroDivisionError:
    raise ValueError from None

Traceback (most recent call last):
  File "<pyshell#30>", line 4, in <module>
    raise ValueError from None
ValueError

2. 多個except子句

??如果你運行前一節(jié)的程序澜驮,并在提示時輸入一個非數(shù)字值陷揪,將引發(fā)另一種異常。

Enter the first number: 10
Enter the second number: 'Hello'
Traceback (most recent call last):
  File "<pyshell#33>", line 3, in <module>
    y = int(input('Enter the second number'))
ValueError: invalid literal for int() with base 10: "'hello'"

??由于該程序中的except子句只捕獲ZeroDivisionError異常杂穷,這種異常將成為漏網(wǎng)之魚悍缠,導(dǎo)致程序終止。為同時捕獲這種異常亭畜,可在try/except語句中再添加一個except子句扮休。

try:
    x = int(input('Enter the first number:'))
    y = int(input('Enter the second number:'))
    print(x / y)
except ZeroDivisionError:
    print("第二個數(shù)字不能為0")
except ValueError:
    print("這不是一個數(shù)字")

??try語句按照如下方式工作:
??首先,執(zhí)行try子句(在關(guān)鍵字try和關(guān)鍵字except之間的語句)拴鸵。
??如果沒有發(fā)生異常玷坠,忽略except子句,try子句執(zhí)行后結(jié)束劲藐。如果在執(zhí)行try子句的過程中發(fā)生異常八堡,try子句余下的部分會被忽略。如果異常的類型和except之后的名稱相符聘芜,對應(yīng)的except子句就會被執(zhí)行兄渺。最后執(zhí)行try語句之后的代碼。如果沒有一個異常與任何except匹配汰现,這個異常就會傳遞到上層的try中挂谍。一個try語句可能包含多個except子句,分別處理不同的異常瞎饲,但最多只有一個分支會被執(zhí)行口叙。
??處理程序?qū)⒅会槍?yīng)try子句中的異常進(jìn)行處理,而不會處理其他異常語句中的異常。
??注意到異常處理并不會導(dǎo)致代碼混亂,而添加大量的if語句來檢查各種可能的錯誤狀態(tài)將導(dǎo)致代碼的可讀性極差蒋搜。

3. 一箭雙雕

??如果要使用一個except子句捕獲多種異常垢啼,可在一個元組中指定這些異常,如下所示:

try:
    x = int(input('Enter the first number:'))
    y = int(input('Enter the second number:'))
    print(x / y)
except (ZeroDivisionError, TypeError, ValueError, NameError):
    print("你的數(shù)字是偽造的")

??在上述代碼中,如果用戶輸入字符串、其他非數(shù)字值或輸入的第二個數(shù)為零,都將打印同樣的錯誤消息启具。當(dāng)然,僅僅打印錯誤消息幫助不大珊泳。另一種解決方案是不斷地要求用戶輸入數(shù)字富纸,直到能夠執(zhí)行除法運算為止囤踩,(6)將介紹如何這樣做。
??這樣做有什么好處呢晓褪?假如我們希望多個except子句輸出同樣的信息堵漱,就沒有必要在幾個except子句中重復(fù)輸入語句,放到一個異常塊中即可涣仿。
??在except子句中勤庐,異常兩邊的圓括號很重要。一種常見的錯誤是省略這些括號好港,這可能導(dǎo)致你不想要的結(jié)果愉镰,其中的原因請參閱下一節(jié)。

4. 捕獲對象

??要在except子句中訪問異常對象本身钧汹,可使用兩個而不是一個參數(shù)丈探。(請注意,即便是在你捕獲多個異常時拔莱,也只向except提供了一個參數(shù)—一個元組碗降。)需要讓程序繼續(xù)運行并記錄錯誤(可能只是向用戶顯示)時,這很有用塘秦。如果希望在except子句中訪問異常對象本身讼渊,也就是看到一個異常對象真正的異常信息,而不是輸出自己定義的異常信息尊剔,可以使用as e的形式爪幻,我們稱之為捕捉對象
??下面的示例程序打印發(fā)生的異常并繼續(xù)運行:

try:
    x = int(input('Enter the first number:'))
    y = int(input('Enter the second number:'))
    print(x / y)
except (ZeroDivisionError, ValueError) as e:
    print(e)
#division by zero
#invalid literal for int() with base 10: "'s'"

??在這個小程序中须误,except子句也捕獲兩種異常挨稿,但由于你同時顯式地捕獲了對象本身,因此可將其打印出來京痢,讓用戶知道發(fā)生了什么情況奶甘。(6)將介紹這種技術(shù)的另一種更有用的用途。

5. 一網(wǎng)打盡

??即使程序處理了好幾種異常历造,還是可能有一些漏網(wǎng)之魚。例如船庇,對于前面執(zhí)行除法運算的程序吭产,如果用戶在提示時不輸入任何內(nèi)容就按回車鍵,將出現(xiàn)一條錯誤消息鸭轮,還有一些相關(guān)問題出在什么地方的信息(棧跟蹤)臣淤,如下所示:

Traceback (most recent call last):
…
invalid literal for int() with base 10: ''

??這種異常未被try/except語句捕獲,因為你沒有預(yù)測到這種問題窃爷,也沒有采取相應(yīng)的措施邑蒋。在這些情況下姓蜂,與其使用并非要捕獲這些異常的try/except語句將它們隱藏起來,還不如讓程序馬上崩潰医吊,因為這樣你就知道什么地方除了問題钱慢。
??然而,如果你就是要使用一段代碼捕獲所有的異常卿堂,只需在except語句中不指定任何異常類即可束莫。

try:
    x = int(input('Enter the first number:'))
    y = int(input('Enter the second number:'))
    print(x / y)
except:
    print('Something wrong happened …')

??現(xiàn)在,用戶輸入什么錯誤信息都可以報錯草描±缆蹋可以在except子句中忽略所有異常類,從而讓程序輸出自己定義的異常信息穗慕。
??但是饿敲,像這樣捕獲所有的異常很危險,因為這不僅會隱藏你有心理準(zhǔn)備的錯誤逛绵,還會隱藏你沒有考慮過的錯誤怀各。這還將捕獲用戶使用Ctrl + C終止執(zhí)行的企圖、調(diào)用函數(shù)sys.exit來終止執(zhí)行的企圖等暑脆。在大多數(shù)情況下渠啤,更好的選擇是使用except Exception as e并對異常對象進(jìn)行檢查。這樣做將讓不是從Exception派生而來的為數(shù)不多的異常成為漏網(wǎng)之魚添吗,其中包括SystemExitKeyboardInterrupt沥曹,因為它們是從BaseException(Exception的超類)派生而來的。

6. 萬事大吉時

??在有些情況下碟联,在沒有出現(xiàn)異常時執(zhí)行一個代碼塊很有用妓美。為此,可像條件語句和循環(huán)一樣鲤孵,給try/except語句添加一個else子句壶栋。

try:
    print('A simple tasl')
except:
    print('what? Something went wrong?')
else:
    print('Ah … It went as planned.')

??如果你運行這些代碼,輸出如下:

A simple tasl
Ah … It went as planned.

??通過使用else子句普监,可實現(xiàn)3.(3)所說的循環(huán)

while True:
    try:
        x = int(input('Enter the first number:'))
        y = int(input('Enter the second number:'))
        value x / y
        print('x / y is ', value)
    except:
        print('Invalid input. Please try again')
    else:
        break

??在這里贵试,僅當(dāng)沒有引發(fā)異常時,才會跳出循環(huán)凯正。換而言之毙玻,只要出現(xiàn)錯誤,程序就會要求用戶提供新的輸入廊散。
??前面說過桑滩,一種更佳的替代方案是使用空的except子句來捕獲所有屬于類Exception的異常。你不能完全確定這將捕獲所有的異常允睹,因為try/except語句中的代碼可能使用舊式的字符串異吃俗迹或引發(fā)并非從Exception派生而來的異常幌氮。然而,如果使用except Exception as e胁澳,就可利用3.(4)節(jié)介紹的技巧在這個小型除法程序中打印更有用的錯誤消息该互。

while True:
    try:
        x = int(input('Enter the first number:'))
        y = int(input('Enter the second number:'))
        value x / y
        print('x / y is ', value)
    except Exception as e:
        print('Invalid input:', e)
        print('please try again!')
    else:
        break

??如果在try子句執(zhí)行時沒有發(fā)生異常,就會執(zhí)行else語句后面的語句听哭。使用else子句比把所有語句都放在try子句里更好慢洋,這樣可以避免一些意想不到而except又沒有捕獲的異常。
??當(dāng)程序沒有發(fā)生異常時陆盘,通過添加一個else子句做一些事情(比如輸出一些信息)很有用普筹,可以幫助我們更好地判斷程序的執(zhí)行情況。

7. 最后

??最后隘马,還有finally子句太防,可用于在發(fā)生異常時執(zhí)行清理工作。這個子句是與try子句配套的酸员,try/finally語句無論發(fā)生異常與否都將執(zhí)行最后的代碼蜒车。

x = None
try:
    x = 1 / 0
finally:
    print('Cleaning up!不管怎么樣我都會先展示在最前面')
    del x

??在上述示例中,finally子句被執(zhí)行了幔嗦,不管try子句中發(fā)生什么異常酿愧,都將執(zhí)行finally子句。為何在try子句之前初始化x呢邀泉?因為如果不這樣做嬉挡,ZeroDivisionError將導(dǎo)致根本沒有機(jī)會給它賦值,進(jìn)而導(dǎo)致在finally子句中對其執(zhí)行del時引發(fā)未捕獲的異常汇恤。
??如果運行這個程序庞钢,它將在執(zhí)行清理工作后崩潰。
??Cleaning up! 不管怎么樣我都會先展示在最前面

Traceback (most recent call last):
  File "<pyshell#42>", line 2, in <module>
    x = 1 / 0
ZeroDivisionError: division by zero

??雖然使用del來刪除變量是相當(dāng)愚蠢的清理措施因谎,但finally子句非常適合用于確保文件或網(wǎng)絡(luò)套接字等得以關(guān)閉基括,這將在第14章介紹。
??也可在一條語句中同時包含try财岔、except风皿、finallyelse(或其中的3個),但要記得elseexcept之后匠璧,finally在exceptelse之后桐款。

try:
    1/0
except ZeroDivisionError:
    print('Division by zero')
else:
    print('That went well')
finally:
    print('cleaning up.')
#Division by zero
#cleaning up.
finally子句在關(guān)閉文件或數(shù)據(jù)庫連接時非常有用。

8. 補(bǔ)充和總結(jié)

??注意:如果拋出父類異常患朱,在子類不會再獲取鲁僚。
??如下:

try:
    fun()
except Exception as e:
    raise Exception
except ImportError as e:
    raise ImportError
finally:
    pass

??在上面的例子中炊苫,下面的ImportError就不會被拋出裁厅,應(yīng)為ImportError繼承Exception冰沙,但是可以把Exception放在后面是可以的

try:
    suite1          #測試語句塊
except exception1:
    suite2          #如果測試語句suite1中發(fā)生exception1異常時執(zhí)行
except (exception2,exception3):
    suite3          #如果測試語句suite1中發(fā)生元組中任意異常時執(zhí)行
except exception4 as reason:    #as把異常的原因賦值給reason
    suite4          #如果測試語句suite1發(fā)生exception4的異常時執(zhí)行
except:
    suite5          #如果測試語句suite1發(fā)生異常在所列出的異常之外時執(zhí)行
else:
    suite5          #如果測試語句塊suite1中沒有發(fā)生異常時執(zhí)行
finally:
    suit6           #不管測試語句suite1中又沒有發(fā)生異常都會執(zhí)行

??所有錯誤類型都繼承自BaseException

四、異常和函數(shù)

??異常和函數(shù)有著天然的聯(lián)系执虹。如果不處理函數(shù)中引發(fā)的異常拓挥,它將向上傳播到調(diào)用函數(shù)的地方。如果在那里也未得到處理袋励,異常將繼續(xù)傳播侥啤,直至到達(dá)主程序(全局作用域)。如果主程序中也沒有異常處理程序茬故,程序?qū)⒔K止并顯示棧跟蹤消息盖灸。來看一個示例。

>>> def faulty():
        raise Exception('Something is wrong')
>>> def ignore_exception():
        faulty()
>>> def handle_exception():
        try:
            faulty()
        except:
            print('Exception handled')

>>> ignore_exception()

??結(jié)果如下

Traceback (most recent call last):
  File "C:/Users/MIC/Desktop/test1.py", line 11, in <module>
    ignore_exception()
  File "C:/Users/MIC/Desktop/test1.py", line 4, in ignore_exception
    faulty()
  File "C:/Users/MIC/Desktop/test1.py", line 2, in faulty
    raise Exception('Something is wrong')
Exception: Something is wrong
>>> handle_exception()
Exception handled

??如你所見磺芭,faulty中引發(fā)的異常依次從faultyignore_exception向外傳播赁炎,最終導(dǎo)致顯示一條棧跟蹤消息。調(diào)用handle_exception時钾腺,異常最終傳播到handle_exception,并被這里的try/except語句處理徙垫。
??注意:異常信息是以堆棧的形式被拋出的,因而是從下往上查看的放棒。所謂堆棧姻报,就是最先被發(fā)現(xiàn)的異常信息最后被輸出,也被稱作先進(jìn)后出间螟。

五吴旋、異常之禪

??異常處理并不是很復(fù)雜。如果你知道代碼可能引發(fā)某種異常寒亥,且不希望出現(xiàn)這種異常時程序終止并顯示站跟蹤消息邮府,可添加必要的try/except或try/finally語句(或結(jié)合使用)來處理它。
??有時候溉奕,可使用條件語句來達(dá)成異常處理實現(xiàn)的目標(biāo)褂傀,但這樣編寫出來的代碼可能不那么自然,可讀性也沒那么高加勤。另一方面仙辟,有些任務(wù)使用if/else完成時看似很自然,但實際上使用try/except來完成要好得多鳄梅。下面來看兩個示例叠国。
??假設(shè)有一個字典,你要在指定的鍵存在時打印與之相關(guān)聯(lián)的值戴尸,否則什么都不做粟焊。實現(xiàn)這種功能的代碼可能類似于下面這樣:

def describe_person(person):
    print('Description of', person['name'])
    print('Age:', person['age'])
if 'occupation' in person;
    print('Occupation:', person['occupation'])

??如果你調(diào)用這個函數(shù),并向它提供一個包含姓名Throatwobbler Mangrove和年齡42的字典,輸出將如下:

Description of Throatwobbler Mangrove
Age: 42

??如果你在這個字典中添加職業(yè)camper项棠,輸出將如下:

Description of Throatwobbler Mangrove
Age: 42
Occupation: camper

??這段代碼很直觀悲雳,但效率不高,因為它必須兩次查找'Occupation'鍵:一次檢查這個鍵是否存在(在條件中)香追,另一次獲取這個鍵關(guān)聯(lián)的值合瓢,以便將其打印出來。下面是另一種解決方案:

def describe_person(person):
    print('Description of', person['name'])
    print('Age:', person['age'])
    try:
        print('Occupation:', person['occupation'])
    except KeyError: pass

??在這里透典,函數(shù)直接假設(shè)存在'Occupation:'鍵晴楔。如果這種假設(shè)正確,就能省點事:直接獲取并打印值峭咒,而無需檢查這個鍵是否存在税弃。如果這個鍵不存在,將引發(fā)KeyError凑队,而except子句將捕獲這個異常钙皮。
??你可能發(fā)現(xiàn),檢查對象是否包含特定的屬性時顽决,try/except也很有用短条。例如,要檢查一個對象是否包含屬性write,可使用類似于下面的代碼:

try:
    obj.write
except AttributeError:
    print('The object is not writeable')
else:
    print('The object is writeable')

??在這里才菠,try子句只是訪問屬性write茸时,而沒有使用它來做任何事情。如果引發(fā)了AttributeError異常赋访,說明對象沒有屬性write可都,否則就說明有這個屬性。這種解決方案可代替7.2.9節(jié)介紹的使用getattr的解決方案蚓耽,而且更自然渠牲。具體使用哪種解決方案,在很大程度上取決于個人喜好步悠。
??在很多情況下签杈,相比于使用if/else,使用try/except語句更自然鼎兽,也更符合Python的風(fēng)格答姥。因此你應(yīng)養(yǎng)成盡可能使用try/except語句的習(xí)慣。

六谚咬、不那么異常的情況

??如果你只想發(fā)出警告鹦付,指出情況偏離了正規(guī),可使用模塊warnings中的函數(shù)warn择卦。

>>> from warnings import warn
>>> warn("I've got a bad feeling about this.")
Warning (from warnings module):
  File "C:/Users/MIC/Desktop/test1.py", line 1
    def faulty():
UserWarning: I've got a bad feeling about this.

??警告只顯示一次敲长。如果再運行最后一行代碼郎嫁,什么事情都不會發(fā)生。
??如果其他代碼在使用你的模塊祈噪,可使用模塊warning中的函數(shù)filterwarning來抑制你發(fā)出的警告(或特定類型的警告)行剂,并指定要采取的措施,如"error"或"ignore"钳降。

>>> from warnings import filterwarnings
>>> filterwarnings("ignore")
>>> warn("Anyone out there?")
>>> filterwarnings("error")
>>> warn("Something is very wrong!")
Traceback (most recent call last):
  File "<pyshell#51>", line 1, in <module>
    warn("Something is very wrong!")
UserWarning: Something is very wrong!

??如你所見,引發(fā)的異常為UserWaining腌巾。發(fā)出警告時遂填,可指定將引發(fā)的異常(即警告類型),但必須是Warning的子類澈蝙。如果將警告轉(zhuǎn)換為錯誤吓坚,將使用你指定的異常。另外灯荧,還可根據(jù)異常來過濾特定類型的警告礁击。

>>> filterwarnings("error")
>>> warn("This function is really old ...", DeprecationWarning) #指定異常
Traceback (most recent call last):
  File "<pyshell#54>", line 1, in <module>
    warn("This function is really old ...", DeprecationWarning)
DeprecationWarning: This function is really old ...
>>> filterwarnings("ignore", category=DeprecationWarning) #指定過濾掉的異常
>>> warn("Another deprecation warning.", DeprecationWarning)
>>> warn("Something else.")
Traceback (most recent call last):
  File "<pyshell#57>", line 1, in <module>
    warn("Something else.")
UserWarning: Something else.

??除上述基本用途外,模塊warnings還提供了一些高級功能逗载。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哆窿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子厉斟,更是在濱河造成了極大的恐慌挚躯,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擦秽,死亡現(xiàn)場離奇詭異码荔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)感挥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門缩搅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人触幼,你說我怎么就攤上這事硼瓣。” “怎么了置谦?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵巨双,是天一觀的道長。 經(jīng)常有香客問我霉祸,道長筑累,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任丝蹭,我火速辦了婚禮慢宗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己镜沽,他們只是感情好敏晤,可當(dāng)我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缅茉,像睡著了一般嘴脾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蔬墩,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天译打,我揣著相機(jī)與錄音,去河邊找鬼拇颅。 笑死奏司,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的樟插。 我是一名探鬼主播韵洋,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼黄锤!你這毒婦竟也來了搪缨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鸵熟,失蹤者是張志新(化名)和其女友劉穎勉吻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旅赢,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡齿桃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了煮盼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片短纵。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖僵控,靈堂內(nèi)的尸體忽然破棺而出香到,到底是詐尸還是另有隱情,我是刑警寧澤报破,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布悠就,位于F島的核電站,受9級特大地震影響充易,放射性物質(zhì)發(fā)生泄漏梗脾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一盹靴、第九天 我趴在偏房一處隱蔽的房頂上張望炸茧。 院中可真熱鬧瑞妇,春花似錦、人聲如沸梭冠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽控漠。三九已至蔓倍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盐捷,已是汗流浹背偶翅。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留毙驯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓灾测,卻偏偏與公主長得像爆价,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子媳搪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,585評論 2 359

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

  • 一铭段、簡介 Python最強(qiáng)大的結(jié)構(gòu)之一就是它的異常處理能力,所有的標(biāo)準(zhǔn)異常都使用類來實現(xiàn)秦爆,都是基類Exceptio...
    隨風(fēng)化作雨閱讀 3,077評論 0 1
  • python提供了兩個非常重要的功能來處理python程序在運行中出現(xiàn)的異常和錯誤等限。你可以使用該功能來調(diào)試pyth...
    _寧采臣閱讀 1,027評論 0 10
  • 一爸吮、錯誤和異常 1、錯誤 從軟件方面來講望门,錯誤通常是語法或邏輯上的形娇。語法錯誤會導(dǎo)致程序代碼不能被解釋器解釋,這些錯...
    常大鵬閱讀 1,347評論 0 6
  • 一、概要 ? 一個程序即使沒有任何語法錯誤厨剪,即使解題的邏輯也正確哄酝,在執(zhí)行的時候仍然可能出現(xiàn) 各種“運行時錯誤”,導(dǎo)...
    唯老閱讀 428評論 0 1
  • 泥土下祷膳,記憶張狂穿梭尋求突破 光陰飛逝陶衅,靈魂碎裂轉(zhuǎn)身離去 碧瞳泣血,往日的痕跡蜿蜒而過 漸逝的風(fēng)直晨,天空沒留下影子 ...
    月影007閱讀 192評論 4 1