Python中的異常處理

今天我們來說說Python的異常處理,在說異常處理之前我們先來了解下寄猩,Python中有哪些常見的錯(cuò)誤類型嫉晶。

在Python中,當(dāng)代碼中有錯(cuò)誤時(shí)田篇,程序默認(rèn)會在終端中將錯(cuò)誤類型和原因打印出來:

以下是Python中一些常用錯(cuò)誤類型:

  1. SyntaxError(語法錯(cuò)誤)
print('函數(shù)最后沒有加小括號'

#運(yùn)行程序后報(bào)錯(cuò) SyntaxError: unexpected EOF while parsing
  1. NameError(名稱錯(cuò)誤)
if not_defined > 0:
    print("NOk")

#運(yùn)行程序后報(bào)錯(cuò) NameError: name 'not_defined' is not defined
  1. LookupError (查詢錯(cuò)誤)
li = [1, 2, 3]
li[1024]

#運(yùn)行程序后報(bào)錯(cuò) IndexError: list index out of range
di = {'code':'JD', 'price':42}
di['CEO']

#運(yùn)行程序后報(bào)錯(cuò) KeyError: 'CEO'
  1. ArithmeticError(運(yùn)算錯(cuò)誤)
1/0
#運(yùn)行程序后報(bào)錯(cuò) ZeroDivisionError: division by zero
  1. TypeError(類型錯(cuò)誤)
days = 365 + '1004'
#運(yùn)行程序后報(bào)錯(cuò) TypeError: unsupported operand type(s) for +: 'int' and 'str'
  1. ValueError(值錯(cuò)誤)
int('永遠(yuǎn)有多遠(yuǎn)')
#運(yùn)行程序后報(bào)錯(cuò) ValueError: invalid literal for int() with base 10: '永遠(yuǎn)有多遠(yuǎn)'
  1. AttributeError(屬性錯(cuò)誤)
a = 1
a.append(2)
#運(yùn)行程序后報(bào)錯(cuò) AttributeError: 'int' object has no attribute 'append'
  1. OSError(系統(tǒng)錯(cuò)誤)
f = open('No Such File.txt')
#運(yùn)行程序后報(bào)錯(cuò) FileNotFoundError: [Errno 2] No such file or directory: 'No Such File.txt'
  1. ImportError(導(dǎo)入錯(cuò)誤)
from numpy import sqr
#運(yùn)行程序后報(bào)錯(cuò) ImportError: cannot import name 'sqr' from 'numpy'
  1. ModuleNotFoundError(未找到模塊錯(cuò)誤)
import numq
#運(yùn)行程序后報(bào)錯(cuò) ModuleNotFoundError: No module named 'numq'
  1. StopIteration(迭代停止錯(cuò)誤)
i = iter([1,2,3])
print(next(i))
print(next(i))
print(next(i))
print(next(i))

#運(yùn)行程序后報(bào)錯(cuò) StopIteration:

看到這里替废,你一定會有一個(gè)疑問,Python怎么有那么多不同的錯(cuò)誤分類呀泊柬,我都需要一一全都記下來嗎椎镣?
就個(gè)人學(xué)習(xí)的經(jīng)驗(yàn)來說,可以先以了解為主兽赁,在后續(xù)實(shí)際應(yīng)用中状答,記住與自己代碼相關(guān)的錯(cuò)誤類型即可冷守。

隨后,我們來說說今天的主題剪况,異常處理教沾,我們首先需要明白的是,我們無法完全阻止錯(cuò)誤發(fā)生译断,但是可以提前預(yù)防以至于程序不會崩潰授翻。這個(gè)提前預(yù)防的動(dòng)作稱為異常處理(exception handling),異常處理就是為了防患于未然孙咪。

從以上的錯(cuò)誤類型我們知道堪唐,Python 在程序報(bào)錯(cuò)時(shí)會返回錯(cuò)誤類型和信息,我們可以提前去捕捉我們能預(yù)計(jì)到的及無法預(yù)計(jì)到的錯(cuò)誤類型翎蹈,并做相應(yīng)的處理淮菠。

接下來,我們來介紹幾種典型的異常處理方式:

1. Try-Except
異常處理最常見的語句就是 try-except 組合荤堪,細(xì)分又有三種類型:

(1) 知道錯(cuò)誤但不確定類型合陵,用 except Exception


except Exception

例子:

def divide(a, b):
    try:
        c = a / b
        print(f"Result = {c:.4f}.")
    except Exception as err:
        print(f'因子是0,無法進(jìn)行相除! 具體錯(cuò)誤為:{err}')

divide(10, 0) #因子是0澄阳,無法進(jìn)行相除! 具體錯(cuò)誤為:division by zero

這里解釋下:
except Exception as err 的含義是將任意異常定義為一個(gè)err對象拥知,后續(xù)可將err轉(zhuǎn)為字符串打印出來,程序會打印錯(cuò)誤原因碎赢,如需同時(shí)打印錯(cuò)誤類型和原因低剔,則需要使用repr(err)。

(2)知道錯(cuò)誤而且確定類型肮塞,用 except some_exception


except some_exception

例子:

def divide(a, b):
    try:
        c = a / b
        print(f"Result = {c:.4f}.")
    except ZeroDivisionError:
        print(f'因子是0襟齿,無法進(jìn)行相除! ')

divide(10, 0) #因子是0,無法進(jìn)行相除!

(3)知道錯(cuò)誤而且有多個(gè)錯(cuò)誤
用多個(gè) except

用 except (exc_1, exc_2, ... exc_n)


多個(gè)錯(cuò)誤

例子:

def divide(a, b):
    try:
        c = a / b
        d = cc + 1
        print(f"Result = {c:.4f}.")
    except ZeroDivisionError:
        print('因子是0枕赵,無法進(jìn)行相除!')
    except NameError:
        print('變量名未定義猜欺!')

divide(10, 2) #變量名未定義!
divide(10, 0) #因子是0拷窜,無法進(jìn)行相除!

有時(shí)替梨,我們也可以對多個(gè)錯(cuò)誤進(jìn)行統(tǒng)一處理,比如:

except (ZeroDivisionError装黑,NameError):
    print('Error occurred!')

實(shí)際工作中弓熏,我們也會遇到不同錯(cuò)誤類型恋谭,做差分處理的情況,比如控制機(jī)械手臂時(shí)挽鞠,如遇到sockets連接丟失的異常時(shí)疚颊,可以做重連操作狈孔,遇到控制指令返回超時(shí)的異常可以做提示重試的處理材义,其他任意錯(cuò)誤則終止機(jī)械手臂的控制均抽,這樣代碼既智能又安全。

    try:
        動(dòng)作
    except SocketsError:
        重連處理
    except NoResponseError:
        提示重試處理
    except Exception:
        停止控制

p.s 以上SocketsError和NoResponseError為自建的錯(cuò)誤類型其掂,Exception為所有其他異常即所有其他錯(cuò)誤類型油挥,程序出錯(cuò)時(shí)會進(jìn)入對應(yīng)的一種錯(cuò)誤類型中去。

2. Try-Except-Else

Try-Except-Else

首先要明確的是款熬,else 語句是可有可無的深寥。如果存在,則 else 語句應(yīng)始終在 except 語句之后贤牛。

當(dāng) try 語句下的代碼未發(fā)生異常時(shí)惋鹅,才會執(zhí)行 else 子句下的代碼。
當(dāng) try 語句下的代碼中發(fā)生異常殉簸,則 except 語句將處理異常闰集,else 語句將不會執(zhí)行。

個(gè)人認(rèn)為般卑,Try-Except-Else的存在感并不是很強(qiáng)武鲁,因?yàn)橥耆梢酝ㄟ^在try的最后,添加相應(yīng)的代碼來實(shí)現(xiàn)同樣的功能椭微。

3. Try-Except-Else-Finally

Try-Except-Else-Finally

無論是否發(fā)生異常洞坑,finally 語句始終在 try 語句運(yùn)行之前執(zhí)行。

在實(shí)際工作中蝇率,finally 是非常有用的迟杂。
比如調(diào)用音頻采集卡時(shí),我們希望無論采集成功或異常失敗時(shí)本慕,最終程序都會做一次停止采集的動(dòng)作來釋放資源排拷。這時(shí)我們就可以將停止采集的動(dòng)作放在finally語句中。

4. Raise Exception
除了上面處理異常的操作之外锅尘,我們還可以用 raise 關(guān)鍵詞“拋出”異常监氢,拋出異常可分為兩類:

(1) 拋出內(nèi)置異常
在下例中藤违,如果輸入非整數(shù)浪腐,我們拋出一個(gè) ValueError(注意這是 Python 里面內(nèi)置的異常對象),順帶打印“This is not a positive number”的信息顿乒。

try:
    a = int(input("Enter a positive integer: "))
    if a <= 0:
        raise ValueError("That is not a positive number!")
except ValueError as err:
    print(err)

(2) 拋出自定義異常
這里我們先需要了解如何自定義異常:
在 Python 里议街,所有異常都是 Exception 的子類,因此在定義其類時(shí)需要進(jìn)行繼承璧榄。
class Error(Exception):
class your_exception(Error):

具體代碼如下特漩。

class Error(Exception):
    pass

class NegativePortfolioValueWarning(Error):
    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

隨后吧雹,我們就可以在代碼中,拋出自定義的NegativePortfolioValueWarning異常了涂身。

def portfolio_value(last_worth, current_worth):
    if last_worth < 0 or current_worth < 0:
        raise ValueError('Negative worth!')
    value = current_worth - last_worth
    if value < 0:
        raise NegativePortfolioValueWarning(
        'NegativePortfolioValueWarning', \
        'Negative return. Take a look!')

總結(jié)雄卷,Python中對不同錯(cuò)誤類型做了細(xì)分且分類非常多,實(shí)際代碼調(diào)試過程中蛤售,我們可以通過打印的方式將錯(cuò)誤類型和原因打印出來丁鹉,以便讓程序繼續(xù)運(yùn)行的前提下了解錯(cuò)誤信息。
對于不同的錯(cuò)誤類型悍抑,我們可以做差分處理鳄炉,以便讓程序容錯(cuò)性更好且更智能。
對于自己編寫程序的一些特殊異常搜骡。我們可以自建錯(cuò)誤類型拂盯,并通過raise拋出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末记靡,一起剝皮案震驚了整個(gè)濱河市谈竿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摸吠,老刑警劉巖空凸,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異寸痢,居然都是意外死亡呀洲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門啼止,熙熙樓的掌柜王于貴愁眉苦臉地迎上來道逗,“玉大人,你說我怎么就攤上這事献烦∽仪希” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵巩那,是天一觀的道長吏夯。 經(jīng)常有香客問我,道長即横,這世上最難降的妖魔是什么噪生? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮东囚,結(jié)果婚禮上杠园,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好抛蚁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惕橙,像睡著了一般瞧甩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弥鹦,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天肚逸,我揣著相機(jī)與錄音,去河邊找鬼彬坏。 笑死朦促,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的栓始。 我是一名探鬼主播务冕,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼幻赚!你這毒婦竟也來了禀忆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤落恼,失蹤者是張志新(化名)和其女友劉穎箩退,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佳谦,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡戴涝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钻蔑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啥刻。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖矢棚,靈堂內(nèi)的尸體忽然破棺而出郑什,到底是詐尸還是另有隱情,我是刑警寧澤蒲肋,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布蘑拯,位于F島的核電站,受9級特大地震影響兜粘,放射性物質(zhì)發(fā)生泄漏抛寝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一见剩、第九天 我趴在偏房一處隱蔽的房頂上張望唇礁。 院中可真熱鬧,春花似錦路鹰、人聲如沸贷洲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽优构。三九已至诵叁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钦椭,已是汗流浹背拧额。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留彪腔,地道東北人侥锦。 一個(gè)月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像德挣,于是被迫代替她去往敵國和親恭垦。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

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