【ZZ】python中的異常處理

Python的異常處理能力是很強大的,可向用戶準確反饋出錯信息。在Python中,異常也是對象,可對它進行操做。全部異常都是基類Exception的成員,全部異常都從基類Exception繼承,並且都在exceptions模塊中定義,Python自動將全部異常名稱放在內建命名空間中,因此程序沒必要導入exceptions模塊便可使用異常。
一旦引起並且沒有捕捉SystemExit異常,程序執行就會終止。若是交互式會話遇到一個未被捕捉的SystemExit異常,會話就會終止。
1、異常的捕獲
異常的捕獲有如下幾種方法:
1:使用try和except語句

try:
    block
except [exception,[data…]]:
    block

try:
    block
except [exception,[data...]]:
    block
else:
    block
該種異常處理語法的規則是:
• 執行try下的語句,若是引起異常,則執行過程會跳到第一個except語句。
• 若是第一個except中定義的異常與引起的異常匹配,則執行該except中的語句。
• 若是引起的異常不匹配第一個except,則會搜索第二個except,容許編寫的except數量沒有限制。
• 若是全部的except都不匹配,則異常會傳遞到下一個調用本代碼的最高層try代碼中。
• 若是沒有發生異常,則執行else塊代碼。
示例代碼:

try:
    f = open(「file.txt」,」r」)
except IOError, e:
    print e
捕獲到的IOError錯誤的詳細緣由會被放置在對象e中,而後運行該異常的except代碼塊,也可使用如下方法來捕獲全部的異常:

try:
    a=b
    b=c
except Exception,ex:
    print Exception,":",ex
使用except子句須要注意的事情,就是多個except子句截獲異常時,若是各個異常類之間具備繼承關係,則子類應該寫在前面,不然父類將會直接截獲子類異常,放在後面的子類異常也就不會執行到了。

2:使用try跟finally

try:
    block
finally:
    block
該語句的執行規則是:
• 執行try下的代碼。
• 若是發生異常,在該異常傳遞到下一級try時,執行finally中的代碼。
• 若是沒有發生異常,則執行finally中的代碼。

第二種try語法在不管有沒有發生異常都要執行代碼的狀況下是頗有用的,例如咱們在python中打開一個文件進行讀寫操做,我在操做過程當中無論是否出現異常,最終都是要把該文件關閉的。
這兩種形式相互衝突,使用了一種就不容許使用另外一種,而功能又各異。

2、手工引起引起一個異常
在Python中,要想引起異常,最簡單的形式就是輸入關鍵字raise,後跟要引起的異常的名稱。異常名稱標識出具體的類:Python異常是那些類的對象,執行raise語句時,Python會建立指定的異常類的一個對象,raise語句還可指定對異常對象進行初始化的參數,爲此,請在異常類的名稱後添加一個逗號以及指定的參數(或者由參數構成的一個元組)。
示例代碼:

try:
    raise MyError #本身拋出一個異常
except MyError:
    print 'a error'

raise ValueError,'invalid argument'
捕捉到的內容爲:

type = VauleError
message = invalid argument
3、跟蹤查看異常
發生異常時,Python能「記住」引起的異常以及程序的當前狀態,Python還維護着traceback(跟蹤)對象,其中含有異常發生時與函數調用堆棧有關的信息,異常可能在一系列嵌套較深的函數調用中引起,程序調用每一個函數時,Python會在「函數調用堆棧」的起始處插入函數名,一旦異常被引起,Python會搜索一個相應的異常處理程序。
若是當前函數中沒有異常處理程序,當前函數會終止執行,Python會搜索當前函數的調用函數,並以此類推,直到發現匹配的異常處理程序,或者Python抵達主程序爲止,這一查找合適的異常處理程序的過程就稱爲「堆棧展轉開解」(Stack Unwinding)。解釋器一方面維護着與放置堆棧中的函數有關的信息,另外一方面也維護着與已從堆棧中「展轉開解」的函數有關的信息。

try:
    block
except:
    traceback.print_exc()

4、採用sys模塊回溯最後的異常 python

import sys
try:
    block
except:
    info=sys.exc_info()
    print info[0],":",info[1]

或者以以下的形式: app

import sys
    tp,val,td = sys.exc_info()
sys.exc_info()的返回值是一個tuple, (type, value/message, traceback)
這裏的type是異常的類型,value/message是異常的信息或者參數,traceback包含調用棧信息的對象,從這點上能夠看出此方法涵蓋了traceback。

以上都是錯誤處理的理論知識,接下來咱們要動手設計一個本身的異常處理類,用來記錄異常日誌,將錯誤的日誌按照每小時一個文件的頻率,保存到咱們指定的位置。代碼以下:

#coding:utf-8
#基於python2.6
import logging,os,time,traceback
class LOG:
    def __init__(self,logger):
        self.fileHandlerName = ''
        self.fileHandler = None
        self.loggerName = logger
        self.logger = logging.getLogger(logger)
        self.logger.setLevel(logging.DEBUG)
        self.formatter = logging.Formatter("=========================\ntime:%(asctime)s \nlogger:%(name)s \nlevel:%(levelname)s \nfile:%(filename)s \nfun:%(funcName)s \nlineno:%(lineno)d \nmessage:%(message)s")

        # 控制檯
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(self.formatter)
        self.logger.addHandler(ch)

        path = os.path.abspath(os.path.dirname(__file__)) + '/log/'+self.loggerName+'/'
        print 'log path=',path
    
    def setfh(self):
        fname = time.strftime("%Y%m%d%H")
        if fname!=self.fileHandlerName:
            #移除原來的句柄
            if self.fileHandler!=None : 
                self.logger.removeHandler(self.fileHandler)
            #設置日誌文件保存位置
            path = os.path.abspath(os.path.dirname(__file__)) + '/log/'+self.loggerName+'/'
            print path
            if os.path.isdir(path) == False:
                os.makedirs(path)
            fh = logging.FileHandler(path+fname+'.log')
            fh.setLevel(logging.DEBUG)
            fh.setFormatter(self.formatter)
            self.logger.addHandler(fh)

            self.fileHandlerName = fname
            self.fileHandler = fh
    #格式化日誌內容
    def _fmtInfo(self,msg):
        if len(msg)==0:
            msg = traceback.format_exc()
            return msg
        else:
            _tmp = [msg[0]]
            _tmp.append(traceback.format_exc())
            return '\n**********\n'.join(_tmp)
    #封裝方法
    def debug(self,*msg):
        _info = self._fmtInfo(msg)
        try:
            self.setfh()
            self.logger.debug(_info)
        except:
            print 'mylog debug:' + _info
    def error(self,*msg):
        _info = self._fmtInfo(msg)
        try:
            self.setfh()
            self.logger.error(_info)
        except:
            print 'mylog error:' + _info
    def info(self,*msg):
        _info = self._fmtInfo(msg)
        try:
            self.setfh()
            self.logger.error(_info)
        except:
            print 'mylog info:' + _info
    def warning(self,*msg):
        _info = self._fmtInfo(msg)
        try:
            self.setfh()
            self.logger.error(_info)
        except:
            print 'mylog warning:' + _info
        

if __name__=='__main__':
    log = LOG('fight')
    try:
        print 1/0
    except:
        log.error() #使用系統本身的錯誤描述
    try:
        print 2/0
    except:
        log.error('搞錯了,分母不能爲0') #使用本身的錯誤描述

運行一下,咱們會在該文件目錄下的log/fight下看到一個日誌文件,記錄的描述內容以下: 函數

相關文章
相關標籤/搜索