Python基礎(chǔ)教程之異常詳解
一、摘要
Python使用被稱(chēng)為異常 的特殊對(duì)象來(lái)管理程序執(zhí)行期間發(fā)生的錯(cuò)誤。每當(dāng)發(fā)生讓Python不知所措的錯(cuò)誤時(shí),它都會(huì)創(chuàng)建一個(gè)異常對(duì)象。如果你編寫(xiě)了處理該異常的代碼,程序?qū)⒗^續(xù)運(yùn)行;如果你未對(duì)異常進(jìn)行處理,程序?qū)⑼V?,并顯示一個(gè)traceback,其中包含有關(guān)異常的報(bào)告。
異常是使用try-except 代碼塊處理的。try-except 代碼塊讓Python執(zhí)行指定的操作,同時(shí)告訴Python發(fā)生異常時(shí)怎么辦。使用了try-except 代碼塊時(shí),即便出現(xiàn)異常,程序也將繼續(xù)運(yùn)行:顯示你編寫(xiě)的友好的錯(cuò)誤消息,而不是令用戶(hù)迷惑的traceback
二、異常實(shí)操
處理ZeroDivisionError 異常:try-except&try-except-else
在上述traceback中,指出的錯(cuò)誤ZeroDivisionError 是一個(gè)異常對(duì)象。Python無(wú)法按你的要求做時(shí),就會(huì)創(chuàng)建這種對(duì)象。在這種情況下,Python將停止運(yùn)行程序,并指出引發(fā)了哪種異常,而我們可根據(jù)這些信息對(duì)程序進(jìn)行修改。下面我們將使用try-except告訴Python,發(fā)生這種錯(cuò)誤時(shí)怎么辦
將導(dǎo)致錯(cuò)誤的代碼行print(5/0) 放在了一個(gè)try 代碼塊中。如果try 代碼塊中的代碼運(yùn)行起來(lái)沒(méi)有問(wèn)題,Python將跳過(guò)except 代碼塊;如果try 代碼塊中的代碼導(dǎo)致了錯(cuò)誤,Python將查找這樣的except 代碼塊,并運(yùn)行其中的代碼,即其中指定的錯(cuò)誤與引發(fā)的錯(cuò)誤相同,在這個(gè)示例中,try 代碼塊中的代碼引發(fā)了ZeroDivisionError 異常,因此Python指出了該如何解決問(wèn)題的except 代碼塊,并運(yùn)行其中的代碼。這樣,用戶(hù)看到的是一條友好的錯(cuò)誤消息,而不是traceback,如果try-except 代碼塊后面還有其他代碼,程序?qū)⒔又\(yùn)行,因?yàn)橐呀?jīng)告訴了Python如何處理這種錯(cuò)誤
使用異常避免崩潰:
發(fā)生錯(cuò)誤時(shí),如果程序還有工作沒(méi)有完成,妥善地處理錯(cuò)誤就尤其重要。這種情況經(jīng)常會(huì)出現(xiàn)在要求用戶(hù)提供輸入的程序中;如果程序能夠妥善地處理無(wú)效輸入,就能再提示用戶(hù)提供有效輸入,而不至于崩潰。
print("Give me two numbers, and I'll divide them.") print("Enter 'q' to quit.") while True: first_number = input("\nFirst number: ") if first_number == 'q': break second_number = input("Second number: ") if second_number == 'q': break answer = int(first_number) / int(second_number) print(answer)
這個(gè)程序沒(méi)有采取任何處理錯(cuò)誤的措施,因此讓它執(zhí)行除數(shù)為0的除法運(yùn)算時(shí),它將崩潰:
Give me two numbers, and I'll divide them. Enter 'q' to quit. First number: 5 Second number: 0 Traceback (most recent call last): File "division.py", line 9, in <module> answer = int(first_number) / int(second_number) ZeroDivisionError: division by zero
程序崩潰可不好,但讓用戶(hù)看到traceback也不是好主意。不懂技術(shù)的用戶(hù)會(huì)被它們搞糊涂,而且如果用戶(hù)懷有惡意,他會(huì)通過(guò)traceback獲悉你不希望他知道的信息。例如,他將知道你的程序文件的名稱(chēng),還將看到部分不能正確運(yùn)行的代碼。有時(shí)候,訓(xùn)練有素的攻擊者可根據(jù)這些信息判斷出可對(duì)你的代碼發(fā)起什么樣的攻擊。
通過(guò)將可能引發(fā)錯(cuò)誤的代碼放在try-except 代碼塊中,可提高這個(gè)程序抵御錯(cuò)誤的能力。錯(cuò)誤是執(zhí)行除法運(yùn)算的代碼行導(dǎo)致的,因此我們需要將它放到try-except 代碼塊中。這個(gè)示例還包含一個(gè)else 代碼塊;依賴(lài)于try 代碼塊成功執(zhí)行的代碼都應(yīng)放到else 代碼塊中:
print("Give me two numbers, and I'll divide them.") print("Enter 'q' to quit.") while True: first_number = input("\nFirst number: ") if first_number == 'q': break second_number = input("Second number: ") try: answer = int(first_number) / int(second_number) except ZeroDivisionError: print("You can't divide by 0!") else: print(answer)
讓Python嘗試執(zhí)行try 代碼塊中的除法運(yùn)算,這個(gè)代碼塊只包含可能導(dǎo)致錯(cuò)誤的代碼。依賴(lài)于try 代碼塊成功執(zhí)行的代碼都放在else 代碼塊中;在這個(gè)示例中,如果除法運(yùn)算成功,我們就使用else 代碼塊來(lái)打印結(jié)果。except 代碼塊告訴Python,出現(xiàn)ZeroDivisionError 異常時(shí)該怎么辦。如果try 代碼塊因除零錯(cuò)誤而失敗,我們就打印一條友好的消息,告訴用戶(hù)如何避免這種錯(cuò)誤。程序?qū)⒗^續(xù)運(yùn)行,用戶(hù)根本看不到traceback:
Give me two numbers, and I'll divide them. Enter 'q' to quit. First number: 5 Second number: 0 You can't divide by 0! First number: 5 Second number: 2 2.5 First number: q
try-except-else 代碼塊的工作原理大致如下:Python嘗試執(zhí)行try 代碼塊中的代碼;只有可能引發(fā)異常的代碼才需要放在try 語(yǔ)句中。有時(shí)候,有一些僅在try 代碼塊成功執(zhí)行時(shí)才需要運(yùn)行的代碼;這些代碼應(yīng)放在else 代碼塊中。except 代碼塊告訴Python,如果它嘗試運(yùn)行try 代碼塊中的代碼時(shí)引發(fā)了指定的異常,該怎么辦。通過(guò)預(yù)測(cè)可能發(fā)生錯(cuò)誤的代碼,可編寫(xiě)健壯的程序,它們即便面臨無(wú)效數(shù)據(jù)或缺少資源,也能繼續(xù)運(yùn)行,從而能夠抵御無(wú)意的用戶(hù)錯(cuò)誤和惡意的攻擊。
處理FileNotFoundError 異常:
使用文件時(shí),一種常見(jiàn)的問(wèn)題是找不到文件:你要查找的文件可能在其他地方、文件名可能不正確或者這個(gè)文件根本就不存在。對(duì)于所有這些情形,都可使用try-except 代碼塊以直觀的方式進(jìn)行處理
filename = 'alice.txt' with open(filename) as f_obj: contents = f_obj.read()
當(dāng)我們嘗試打開(kāi)的文件(alice.txt)不存在時(shí),python會(huì)報(bào)如下異常:
Traceback (most recent call last): File "alice.py", line 3, in <module> with open(filename) as f_obj: FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
在上述traceback中,最后一行報(bào)告了FileNotFoundError 異常,這是Python找不到要打開(kāi)的文件時(shí)創(chuàng)建的異常。在這個(gè)示例中,這個(gè)錯(cuò)誤是函數(shù)open() 導(dǎo)致的,因此要處理這個(gè)錯(cuò)誤,必須將try 語(yǔ)句放在包含open() 的代碼行之前:
filename = 'alice.txt' try: with open(filename) as f_obj: contents = f_obj.read() except FileNotFoundError: msg = "Sorry, the file " + filename + " does not exist." print(msg)
分析文本:
split()函數(shù),看看下邊的例子,這個(gè)函數(shù)干了什么
>>> title = "Alice in Wonderland" >>> title.split() ['Alice', 'in', 'Wonderland']
split() 以空格為分隔符將字符串分拆成多個(gè)部分,并將這些部分都存儲(chǔ)到一個(gè)列表中。結(jié)果是一個(gè)包含字符串中所有單詞的列表,雖然有些單詞可能包含標(biāo)點(diǎn)。為計(jì)算Alice in Wonderland 包含多少個(gè)單詞,我們將對(duì)整篇小說(shuō)調(diào)用split() ,再計(jì)算得到的列表包含多少個(gè)元素,從而確定整篇童話大致包含多少個(gè)單詞
filename = 'alice.txt' try: with open(filename) as f_obj: contents = f_obj.read() except FileNotFoundError: msg = "Sorry, the file " + filename + " does not exist." print(msg) else: # 計(jì)算文件大致包含多少個(gè)單詞 words = contents.split() num_words = len(words) print("The file " + filename + " has about " + str(num_words) + " words.")
將文件alice.txt移到了正確的目錄中,讓try 代碼塊能夠成功地執(zhí)行。對(duì)變量contents (它現(xiàn)在是一個(gè)長(zhǎng)長(zhǎng)的字符串,包含童話 Alice in Wonderland 的全部文本)調(diào)用方法split() ,以生成一個(gè)列表,其中包含這部童話中的所有單詞。當(dāng)我們使用len() 來(lái)確定這個(gè)列表的長(zhǎng)度時(shí),就知道了原始字符串大致包含多少個(gè)單詞,我們打印一條消息,指出文件包含多少個(gè)單詞,這些代碼都放在else 代碼塊中,因?yàn)閮H當(dāng)try 代碼塊成功執(zhí)行時(shí)才執(zhí)行它們。輸出指出了文件alice.txt包含多少個(gè)單詞
使用多個(gè)文件:
def count_words(filename): """計(jì)算一個(gè)文件大致包含多少個(gè)單詞""" try: with open(filename) as f_obj: contents = f_obj.read() except FileNotFoundError: msg = "Sorry, the file " + filename + " does not exist." print(msg) else: # 計(jì)算文件大致包含多少個(gè)單詞 words = contents.split() num_words = len(words) print("The file " + filename + " has about " + str(num_words) + " words.") filename = 'alice.txt' count_words(filename)
然后編寫(xiě)一個(gè)循環(huán),調(diào)用這個(gè)函數(shù)讓他分析多個(gè)文件:
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt'] for filename in filenames: count_words(filename)
在filenames列表中的siddhartha.txt文件是不存在的,我們的程序也能正常運(yùn)行,使用try-except 代碼塊提供了兩個(gè)重要的優(yōu)點(diǎn):避免讓用戶(hù)看到traceback;讓程序能夠繼續(xù)分析能夠找到的其他文件。如果不捕獲因找不到siddhartha.txt而引發(fā)的FileNotFoundError 異常,用戶(hù)將看到完整的traceback,而程序?qū)⒃趪L試分析 Siddhartha 后停止運(yùn)行——根本不分析 Moby Dick 和 Little Women
在前一個(gè)示例中,我們告訴用戶(hù)有一個(gè)文件找不到。但并非每次捕獲到異常時(shí)都需要告訴用戶(hù),有時(shí)候你希望程序在發(fā)生異常時(shí)一聲不吭,就像什么都沒(méi)有發(fā)生一樣繼續(xù)運(yùn)行。要讓程序在失敗時(shí)一聲不吭,可像通常那樣編寫(xiě)try 代碼塊,但在except 代碼塊中明確地告訴Python什么都不要做。Python有一個(gè)pass 語(yǔ)句,可在代碼塊中使用它來(lái)讓Python什么都不要做
def count_words(filename): """計(jì)算一個(gè)文件大致包含多少個(gè)單詞""" try: --snip-- except FileNotFoundError: pass else: --snip-- filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt'] for filename in filenames: count_words(filename)
相比于前一個(gè)程序,這個(gè)程序唯一不同的地方是pass 語(yǔ)句?,F(xiàn)在,出現(xiàn)FileNotFoundError 異常時(shí),將執(zhí)行except 代碼塊中的代碼,但什么都不會(huì)發(fā)生。這種錯(cuò)誤發(fā)生時(shí),不會(huì)出現(xiàn)traceback,也沒(méi)有任何輸出。用戶(hù)將看到存在的每個(gè)文件包含多少個(gè)單詞,但沒(méi)有任何跡象表明有一個(gè)文件未找到
pass 語(yǔ)句還充當(dāng)了占位符,它提醒你在程序的某個(gè)地方什么都沒(méi)有做,并且以后也許要在這里做些什么。例如,在這個(gè)程序中,我們可能決定將找不到的文件的名稱(chēng)寫(xiě)入到文件missing_files.txt中。用戶(hù)看不到這個(gè)文件,但我們可以讀取這個(gè)文件,進(jìn)而處理所有文件找不到的問(wèn)題
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
python中class類(lèi)與方法的用法實(shí)例詳解
類(lèi)(class)是python中很重要的一個(gè)概念,也是我們面象對(duì)象編程中最重要的概念主之一,這篇文章主要給大家介紹了關(guān)于python中class類(lèi)與方法用法的相關(guān)資料,需要的朋友可以參考下2022-04-04python繪圖時(shí),坐標(biāo)軸負(fù)號(hào)顯示不出來(lái)的解決
這篇文章主要介紹了python繪圖時(shí),坐標(biāo)軸負(fù)號(hào)顯示不出來(lái)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09Python數(shù)據(jù)處理numpy.median的實(shí)例講解
下面小編就為大家分享一篇Python數(shù)據(jù)處理numpy.median的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Python股票開(kāi)源庫(kù)akshare的具體使用
AKShare是一個(gè)開(kāi)源財(cái)經(jīng)數(shù)據(jù)接口庫(kù),本文主要介紹了Python股票開(kāi)源庫(kù)akshare的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04Python可執(zhí)行文件反編譯教程(exe轉(zhuǎn)py)
python的便利性,使得如今許多軟件開(kāi)發(fā)者、黑客都開(kāi)始使用python打包成exe的方式進(jìn)行程序的發(fā)布,那么Python如何反編譯可執(zhí)行文件,本文就來(lái)介紹一下,感興趣的可以了解一下2021-12-12python之語(yǔ)句mode = 'test' if y&nb
這篇文章主要介紹了python之語(yǔ)句mode = 'test' if y is None else 'train'問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02