官术网_书友最值得收藏!

  • Linux集群之美
  • 余洪春
  • 1783字
  • 2021-01-08 10:57:48

2.5.5 Python異常處理與程序調(diào)試異常

Exception是任何語言必定存在的一部分。Python提供了強(qiáng)大的異常處理機(jī)制,可通過捕獲異常來提高程序的健壯性。異常處理還具有釋放對象、中止循環(huán)的運行等作用。在程序運行的過程中,如果發(fā)生了錯誤,可以事先約定返回一個錯誤代碼,這樣就可以知道是否有錯,以及出錯的原因。在操作系統(tǒng)提供的調(diào)用中,返回錯誤碼非常常見。比如打開文件的函數(shù)open(),成功時返回文件描述符(就是一個整數(shù)),出錯時返回-1值。用錯誤碼來表示是否出錯十分不便,因為應(yīng)該返回的正常結(jié)果會和錯誤碼混在一起,造成調(diào)用者必須用大量的代碼來判斷是否出錯。一旦出錯,還要一級一級上報,直到某個函數(shù)可以處理該錯誤(比如,給用戶輸出一個錯誤信息)。所以高級語言通常都內(nèi)置了一套try...except...finally...的錯誤處理機(jī)制,Python也不例外。

1.try...except語句

try...except語句用于處理問題語句,捕獲可能存在的異常。try子句中的代碼塊用于放置可能出現(xiàn)異常的語句,except子句中的代碼塊用于處理異常。當(dāng)異常出現(xiàn)時,Python會自動生成一個異常對象。該對象包括異常的具體信息,以及異常的種類和錯誤位置。我們舉個簡單的例子:


#!/usr/bin/env python
#-*- coding:utf-8 -*-

try:
    open('test.txt','r')
    #嘗試獲取一個不存在的文件
    print "該文件是正常的"
except IOError:
#捕獲I/O異常,如果是Python 3.7版本,這里是FileNotFoundError異常
    print "該文件不存在"
except:
    print "程序異常!"
#其他異常情況

try...except語句后面還可以添加一個finally語句,這種方式主要用于無論異常是否發(fā)生,finally子句都會被執(zhí)行的情況。所有的finally子句都用于關(guān)閉因異常而不能釋放的系統(tǒng)資源。還是以上面的例子為例,在后面加上finally子句:


#!/usr/bin/env python
#-*- coding:utf-8 -*-

try:
    f = open('test1.py','r')
    try:
        print f.read()
    except:
        print "該文件是正常的"
    finally:
        print "釋放資源"
        f.close()
except IOError:
    print "文件不存在!"

我們用finally語句的本意是想關(guān)閉因異常而不能釋放的系統(tǒng)資源,比如關(guān)閉文件。但隨著語句的增多,try...finally顯然不夠簡潔,用with...as(上下文管理器)語句可以很簡潔地實現(xiàn)以上功能:


with open('test1.py','w') as f:
    f.write('Hello ')
    f.write('World')

這樣不僅能處理出現(xiàn)異常的情況,而且還可以避免出現(xiàn)在open()一個文件后忘記寫close()方法的情況。

此外,當(dāng)程序中出現(xiàn)錯誤時,Python會自動引發(fā)異常,也可以通過raise語句顯式地引發(fā)異常。一旦執(zhí)行了raise語句,raise語句后的代碼將不能被執(zhí)行。示例如下:


#!/usr/bin/env python
#-*- encoding:utf-8 -*-

try:
    s = None
    if s is None:
        print "s是對空對象"
    print len(s)
except TypeError:
    print "空對象是沒有長度的"

第三行程序判斷變量s的值是否為空,如果為空,則拋出異常NameError;由于執(zhí)行了NameError異常,所以該代碼后的代碼將不會被執(zhí)行。

2.調(diào)試

當(dāng)程序中出現(xiàn)異常或錯誤時,最后的解決方法就是調(diào)試程序,那么一般包含哪些方法呢?通常有如下5種方法:

·編輯器自帶的調(diào)試功能

·print方法

·斷言(assert)方法

·logging模塊

·pdb方法

Python的專業(yè)編程器,例如PyCharm IDE本身就帶了Python程序的Debug調(diào)試功能,這里就不進(jìn)行詳細(xì)說明了,下面只針對其余幾種情況來說明。

(1)print方法

print方法很好理解,這也是我們寫程序經(jīng)常用到的一種方法,即我們認(rèn)為某變量有問題或需要知道某變量時,將它打印出來即可,雖然簡單粗暴,但確實有效。但這樣也會帶來一個問題,復(fù)雜的業(yè)務(wù)邏輯中會有大量變量,這樣程序中會充斥著大量的print語句,如果調(diào)試完成以后不注意清理,也會帶來很多問題。

(2)斷言方法

assert語句用于檢測某個條件表達(dá)式是否為真。

用assert代替print是種很好的選擇?想想我們的程序里到處都是print,運行結(jié)果也會包含很多垃圾信息。理論上,程序中有print出現(xiàn)的地方,都可以用assert來代替。如果assert語句斷言失敗,則會引發(fā)AssertionError異常。

舉個簡單的例子:


a = 'hello'
assert len(a) == 1

執(zhí)行下面這段代碼,會報錯:


AssertionError                            Traceback (most recent call last)
<ipython-input-4-ce3ea8375b99> in <module>()
----> 1 assert len(t) <= 1
AssertionError:

(3)logging模塊

當(dāng)Python程序的代碼量達(dá)到一定數(shù)量時,使用logging就是一種好的選擇。logging不僅能輸出到控制臺,還能寫入文件,且能使用TCP協(xié)議將日志信息發(fā)送到網(wǎng)絡(luò),功能十分強(qiáng)大。示例如下:


#!/usr/bin/env python
import logging

logging.debug('debug message')
logging.info('info message')
logging.warn('warn message')
logging.error('error message')
logging.critical('critical message')

執(zhí)行下面這段代碼,結(jié)果如下:


WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

默認(rèn)情況下,logging模塊會將日志打印到屏幕上,日志級別為WARNING(即只有日志級別高于WARNING的信息才會輸出),我們可以在合理的程序中使用logging模塊代替print命令,這樣寫出來的程序在排錯時會非常高效。

(4)pdb方法

使用Python的調(diào)試器pdb可讓程序以單步的方法運行,以便隨時查看程序的執(zhí)行狀態(tài)。

我們先故意寫一個有問題的Python程序,名字叫err.py,內(nèi)容如下:


#!/usr/bin/env python
s = '0'
n = int(s)
print 10/n

然后在Linux環(huán)境下以pdb模式執(zhí)行程序,如下:


python -m pdb test0.py

l表示可以查看代碼全部完整內(nèi)容,n是一步一步執(zhí)行代碼,p +變量名表示可以隨時打印程序中的變量名,這里大家自行演示。

雖然這些方法都有各自的好處,但隨著我們開發(fā)的項目越來越多,代碼量越來越大時,大家會發(fā)現(xiàn),logging模塊才是最有效率的辦法。

主站蜘蛛池模板: 凤阳县| 保康县| 谢通门县| 清水县| 宁波市| 洪江市| 平塘县| 瑞丽市| 水城县| 崇信县| 阿勒泰市| 苗栗县| 永靖县| 平邑县| 肥乡县| 平乡县| 潼南县| 龙口市| 读书| 兰州市| 嘉禾县| 新安县| 建宁县| 邢台县| 林州市| 平乡县| 鹿邑县| 西青区| 大英县| 靖州| 巴南区| 涿州市| 平阴县| 共和县| 襄垣县| 大宁县| 南丰县| 上林县| 宝清县| 疏附县| 衡东县|