Python3.5筆記——第9章 異常

Python3.5筆記

第9章 異常

什么是異常

一般情況下,在Python無法正常處理程序時就會發(fā)生異常。異常是Python的對象,表示一個錯誤。當(dāng)Python腳本發(fā)生異常時,我們需要捕獲并處理異常,否則程序會終止執(zhí)行。如:

print(a)

輸出:

Traceback (most recent call last):
  File "D:/pyspace/hellopython/Chapter9.py", line 1, in <module>
    print(a)
NameError: name 'a' is not defined

異常處理

處理異常,最簡單的是使用try語句處理。try語句的基本格式為:try/except。try/except語句用來檢測try語句塊中的錯誤,從而讓except語句捕獲異常信息并處理。如果你不想在發(fā)生異常時結(jié)束程序,只需要在try語句塊中捕獲異常即可。語法格式如下:

try:
    <語句> #運行別的代碼
except<異常的名字>:
    <語句> #如果在try部分發(fā)生了異常
    

示例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def test_exception(x,y):
    try:
        a = x/y
        print('a=',a)
        return a
    except Exception:
        print('程序發(fā)生異常,被除數(shù)為0')

test_exception(10,0)

輸出:

程序發(fā)生異常,被除數(shù)為0

拋出異常

Python使用raise語句拋出一個指定的異常。使用類時程序會自動創(chuàng)建實例。

#raise Exception

#raise NameError('this is nameerror')

def test_exception2():
    try:
        raise NameError('This is a NameError')
    except NameError:
        print('發(fā)生異常!')
        #raise 如果只想知道是否拋出了異常,不想處理。加上raise語句把異常再次拋出

test_exception2()

輸出(捕獲異常后不添加raise):

發(fā)生異常!

輸出(捕獲異常后添加raise):

Traceback (most recent call last):
發(fā)生異常!
  File "D:/pyspace/hellopython/Chapter9.py", line 26, in <module>
    test_exception2()
  File "D:/pyspace/hellopython/Chapter9.py", line 21, in test_exception2
    raise NameError('This is a NameError')
NameError: This is a NameError

在Python中,內(nèi)建的異常類很多,比如:NameError、SyntaxError、TypeError、ValueError等,可以使用dir函數(shù)列出異常類的內(nèi)容,并用在raise語句中。內(nèi)建的異常類如表格:

異常名稱 描述
Exception 常規(guī)錯誤的基類
AttributeError 對象沒有這個屬性
IOError 輸入/輸出操作失敗
IndexError 序列中沒有此索引(index)
KeyError 映射中沒有這個鍵
NameError 未聲明/初始化對象
SyntaxError 語法錯誤
SystemError 一般解釋器系統(tǒng)錯誤
ValueError 傳入無效的參數(shù)

捕獲多個異常

Python支持在一個try/excpet語句中處理多個異常,語法如下:

try:
    <語句>
except <異常名1>:
    <語句>
except <異常名2>:
    <語句>

示例如下:

def test_expcetion3(a,b):
    try:
        c = a / b
        #c = name
        return c
    except ZeroDivisionError:
        print('除數(shù)不能為0')
    except NameError:
        print('對象未聲明')

test_exception(10,0)

輸出:

程序發(fā)生異常,被除數(shù)為0

使用一個塊捕捉多個異常

如果需要使用一個塊捕捉多個類型異常,可以將它們作為元組列出。使用該方式時,遇到的異常類型是元組中的任意一個,都會走異常流程。實例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def test_expceiton4(a,b):
    try:
        c = a/b
        return c
    except (ZeroDivisionError,NameError,TypeError):
        print('發(fā)生了異常!')

test_expceiton4(10,0)

輸出:

發(fā)生了異常!

如果我們希望多個except字句輸出同樣的信息,就沒必要在幾個except字句中重復(fù)輸入字句,放到一個異常塊中即可。

捕捉對象

如果需要輸出錯誤時的棧堆信息,可以使用as e的形式,我們稱之為捕捉對象。實例如下:

def test_expceiton5(a,b):
    try:
        c = a/b
        return c
    except (ZeroDivisionError,NameError,TypeError) as e:
        print(e)

test_expceiton5(10,0)

輸出:

division by zero

全捕捉

對于逃過了捕獲指定異常的情況,我們根本無法預(yù)測會發(fā)生什么,也無法提前做任何準(zhǔn)備。此時,與其使用不是捕獲異常try/catch語句隱藏異常,不如讓程序立刻崩潰。實例如下:

def test_expceiton5(a,b):
    try:
        c = a/b
        return c
    except:
        print('全捕獲異常')

test_expceiton5(10,'')

輸出:

全捕獲異常

異常中的else

try...except...else...語句,如果在try語句執(zhí)行時沒有發(fā)生異常,就會執(zhí)行else語句后的語句(如果有else)。使用else語句,比把所有語句都放在try字句里更好,這樣可以避免一些意想不到而except有沒捕獲的異常。格式如下:

try:
    <語句>
except<異常名1>:
    <語句>
except<異常名n>:
    <語句>
else:
    <語句> #如果沒有發(fā)生異常

示例如下:

def test_expceiton6(a,b):
    try:
        c = a/b
    except:
        print('全捕獲異常')
    else:
        print('沒有發(fā)生異常')

test_expceiton6(10,5)

輸出:

沒有發(fā)生異常

自定義異常

盡管內(nèi)建異常包含了大部分異常,可以滿足很多要求,但有時還是要創(chuàng)建自己的異常類??梢酝ㄟ^創(chuàng)建一個新的exception類擁有自己的異常,異常應(yīng)該繼承自Exception類,可以直接繼承,也可以間接繼承。

因為錯誤就是類,因此捕獲異常就是捕獲該類的一個實例,我們自己編寫的函數(shù)也可以拋出錯誤。如果要拋出錯誤,那么可以定義一個錯誤類,根據(jù)需要選擇好繼承關(guān)系,然后用raise語句拋出一個錯誤的實例。示例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
# 自定義異常類最好以Error結(jié)尾,方便識別
class MyError(Exception):
    def __init__(self):
        pass

    def __str__(self):
        return 'this is my error'

def my_error_test():
    try:
        raise MyError()
    except MyError as e:
        print('exception e is:',e)

my_error_test()

輸出:

exception e is: this is my error

finally子句

Python中finally子句需要和try語句一起使用,組成try/finally的語句形式,try/finally語句無論是否發(fā)生異常與否都將執(zhí)行最后的代碼。try、except、else、finally語句可以組合使用,執(zhí)行順序為:else在except之后,finally在except和else之后。示例如下:

def use_finally(a,b):
    try:
        c = a/b
        print('c=',c)
    except Exception:
        print('發(fā)生異常')
    else:
        print('順利上岸,沒有發(fā)生異常')
    finally:
        print('不管是否發(fā)生異常,我都會出現(xiàn)!')

use_finally(10,0)#測試發(fā)生異常
#use_finally(10,5)#測試不發(fā)生異常

發(fā)生異常時,輸出:

發(fā)生異常
不管是否發(fā)生異常,我都會出現(xiàn)!

不發(fā)生異常時,輸出:

c= 2.0
順利上岸,沒有發(fā)生異常
不管是否發(fā)生異常,我都會出現(xiàn)!

異常和函數(shù)

如果異常在函數(shù)內(nèi)引發(fā)而不被處理,就會傳播至函數(shù)調(diào)用的地方。如果異常在函數(shù)調(diào)用的地方也沒有被處理,就會繼續(xù)傳播,一直到達主程序。如果在主程序也沒有被處理,異常就會被Python解釋器捕獲,輸出一個錯誤信息,然后退出主程序。示例如下:

def divide_func(a,b):
    return a/b

def exec_divide_func(a,b):
    return divide_func(a,b)*10

def main(a,b):
    return exec_divide_func(a,b)

main(10,0)

輸出:

Traceback (most recent call last):
  File "D:/pyspace/hellopython/Chapter9.py", line 131, in <module>
    main(10,0)
  File "D:/pyspace/hellopython/Chapter9.py", line 129, in main
    return exec_divide_func(a,b)
  File "D:/pyspace/hellopython/Chapter9.py", line 126, in exec_divide_func
    return divide_func(a,b)*10
  File "D:/pyspace/hellopython/Chapter9.py", line 123, in divide_func
    return a/b
ZeroDivisionError: division by zero

由執(zhí)行結(jié)果來看,divide_func函數(shù)中產(chǎn)生的異常通過divide_func和exec_divide_func函數(shù)傳播,exec_divide_func函數(shù)中的異常,通過exec_divide_func和main函數(shù)傳播,傳播到函數(shù)調(diào)用處后由Python解釋器處理,最終拋出棧堆異常。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容