編程入門12:Python異常處理

上一篇:編程入門11:Python面向?qū)ο?/a>

我們在編程時常常要和各種錯誤信息打交道,當(dāng)Python解釋器發(fā)現(xiàn)程序的錯誤時端蛆,就會拋出“異常”(Exception)來提示錯誤——這種情況可能發(fā)生于“編譯時”和“運行時”這兩個不同的階段:Python程序在運行之前要先編譯嫌拣,如果編譯未通過就不會開始運行——你可以在IPython一次交互中輸入包含多條語句的程序來驗證一下(按Ctrl+Enter換行异逐,按Shift+Enter提交):

In [1]: print(2/3)
   ...: print(2///3)
   ...: print("結(jié)束")
  File "<ipython-input-1-90ecc1ce7c0b>", line 2
    print(2///3)
             ^
SyntaxError: invalid syntax


In [2]: print(2/3)
   ...: print(2/0)
   ...: print("結(jié)束")
   ...: 
0.6666666666666666
Traceback (most recent call last):

  File "<ipython-input-2-7d58b37c849b>", line 2, in <module>
    print(2/0)

ZeroDivisionError: division by zero

上面第一段程序的第二句不符合語法,編譯因此中斷并拋出“語法錯誤”(SyntaxError)異常腥例,這就屬于編譯時錯誤酝润;通過編譯的程序在運行期間仍可能出現(xiàn)導(dǎo)致程序中止的問題——上面第二段程序在語法上沒有問題,第一句也正常執(zhí)行了构回,但第二句中除數(shù)為零的運算違反數(shù)學(xué)規(guī)則疏咐,運行因此中止并拋出“除零錯誤”(ZeroDivisionError)異常,這就屬于運行時錯誤茁肠。

運行時錯誤難免會發(fā)生——用戶輸入的數(shù)據(jù)不完整缩举、打開的文件格式不正確或連接的網(wǎng)絡(luò)不通暢等等仅孩,都可能導(dǎo)致拋出異常。開發(fā)者應(yīng)該預(yù)先考慮到各種異常情況京腥,增加相應(yīng)的代碼來處理運行時錯誤以避免程序意外中止溅蛉。所有異常對象都是特定異常類的實例,最基本的異常類是BaseException欠气,通常在編程中需要處理的異常則都繼承自BaseException的子類Exception镜撩。如果想要查看異常類的繼承關(guān)系,可以使用mro方法返回“方法解析順序”(Method Resolution Order)——這實際上就是類的繼承順序宜鸯,一直上溯到object類為止。此外鸿市,你還可以使用raise語句直接“召喚”異常适贸,或使用assert語句“指明”條件來觸發(fā)異常。

In [3]: SyntaxError.mro()
Out[3]: [SyntaxError, Exception, BaseException, object]

In [4]: ZeroDivisionError.mro()
Out[4]: [ZeroDivisionError, ArithmeticError, Exception, BaseException, object]

In [5]: help(Exception.mro)
Help on built-in function mro:

mro(...) method of builtins.type instance
    mro() -> list
    return a type's method resolution order

In [6]: raise Exception("發(fā)生了錯誤")
Traceback (most recent call last):

  File "<ipython-input-6-2b67d8d306dd>", line 1, in <module>
    raise Exception("發(fā)生了錯誤")

Exception: 發(fā)生了錯誤

In [7]: a = 20
   ...: assert a <= 10, "數(shù)值過大"
   ...: 
Traceback (most recent call last):

  File "<ipython-input-7-58c21e2f5947>", line 2, in <module>
    assert a <= 10, "數(shù)值過大"

AssertionError: 數(shù)值過大

Python提供try語句來實現(xiàn)異常處理:“嘗試”執(zhí)行可能出錯的代碼冯遂,如有“異常”就進行相應(yīng)處理——提醒用戶再次輸入蛤肌、檢查文件或重新連網(wǎng)等等裸准,使程序能夠順暢地運行下去。下面我們來看一個非常簡單的計算程序:根據(jù)輸入的算式輸出答案——使用eval函數(shù)能把字符串作為表達式來求值盐肃,但是用戶可能輸入不合法的表達式权悟,導(dǎo)致運行時錯誤的發(fā)生,因此就要使用try語句來處理異常:嘗試運行try代碼段谦铃,如無異常則運行之后的語句榔昔,如有異常就轉(zhuǎn)而執(zhí)行except代碼段,這樣即使用戶輸入錯誤的內(nèi)容嘹朗,程序也不至于崩潰茧彤。

"""calc.py 簡單的計算程序
"""
ans = ""
while True:
    ask = input("輸入算式或回車退出:")
    if ask == "":
        break
    try:
        ans = eval(ask)
    except:
        pass
    print(ans)

以上程序中的pass語句表示什么也不做直接放過,這當(dāng)然不好——正如Python之禪所言“錯誤不可放過”——以下程序捕獲拋出的Exception類(包括其所有繼承者)實例并賦值給變量e壁顶,這樣就能用repr(e)返回異常類型及提示信息溜歪,通知我們具體發(fā)生了什么問題再繼續(xù)運行:

    except Exception as e:
        ans = repr(e)

你可以在try語句中使用多個except子句,捕獲不同類型的異常進行分別處理调衰,例如輸出自定義的提示信息自阱。此外沛豌,你還可以添加一個finally子句,在其中編寫無論是否發(fā)生異常都要“最終”執(zhí)行的代碼加派。

    except SyntaxError:
        ans = "語法不正確"
    except ZeroDivisionError:
        ans = "除數(shù)不能為零"
    except Exception as e:
        ans = "發(fā)生{}錯誤".format(e.__class__.__name__)
    finally:
        print("輸出結(jié)果:", end="")

下面讓我們來看一個在線隨機圖片API的測試程序:訪問指定的“歲月小筑”網(wǎng)址會返回一張隨機圖片的網(wǎng)址芍锦,然后調(diào)用默認瀏覽器打開:

"""urlgetpic.py “歲月小筑”隨機圖片API測試程序
獲取一張隨機圖片的網(wǎng)址并用瀏覽器打開
"""
from urllib.request import urlopen
import webbrowser
url = "http://img.xjh.me/random_img.php?return=url"


def main():
    try:
        pic = urlopen(url).read().decode()
        webbrowser.open("http:" + pic)
    except Exception as e:
        print(repr(e))


if __name__ == "__main__":
    main()
12_pic.jpg

網(wǎng)絡(luò)總會有連不上的時候娄琉,所以訪問在線資源的代碼應(yīng)該用try語句加以保護。

——編程原來這樣……

編程小提示:開放API

API指“應(yīng)用編程接口”(Application Programming Interface)檬输,其作用是讓外部開發(fā)者可以調(diào)用程序的特定功能匈棘,而又無需關(guān)心程序內(nèi)部的細節(jié)。在互聯(lián)網(wǎng)時代逃默,把網(wǎng)絡(luò)服務(wù)封裝成一系列數(shù)據(jù)接口開放出去供第三方開發(fā)者使用簇搅,這就叫做開放API——從更廣泛的意義上講瘩将,任何網(wǎng)站都是API凹耙,你可以編寫程序從網(wǎng)站中獲取所需要的信息,就像調(diào)用本地函數(shù)返回結(jié)果一樣肠仪。

下一篇:編程入門13:Python文本處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肖抱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子异旧,更是在濱河造成了極大的恐慌意述,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吮蛹,死亡現(xiàn)場離奇詭異荤崇,居然都是意外死亡,警方通過查閱死者的電腦和手機潮针,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門术荤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來然低,“玉大人喜每,你說我怎么就攤上這事■ㄈ粒” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵枫笛,是天一觀的道長吨灭。 經(jīng)常有香客問我,道長刑巧,這世上最難降的妖魔是什么喧兄? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮啊楚,結(jié)果婚禮上吠冤,老公的妹妹穿的比我還像新娘。我一直安慰自己恭理,他們只是感情好拯辙,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著颜价,像睡著了一般涯保。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上周伦,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天夕春,我揣著相機與錄音,去河邊找鬼专挪。 笑死及志,一個胖子當(dāng)著我的面吹牛片排,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播速侈,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼率寡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锌畸?” 一聲冷哼從身側(cè)響起勇劣,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎潭枣,沒想到半個月后比默,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡盆犁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年命咐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谐岁。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡醋奠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伊佃,到底是詐尸還是另有隱情窜司,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布航揉,位于F島的核電站塞祈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏帅涂。R本人自食惡果不足惜议薪,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媳友。 院中可真熱鬧斯议,春花似錦、人聲如沸醇锚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搂抒。三九已至艇搀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間求晶,已是汗流浹背焰雕。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芳杏,地道東北人矩屁。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓辟宗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吝秕。 傳聞我的和親對象是個殘疾皇子泊脐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

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