1. 程式人生 > 程式設計 >python 追蹤except資訊方式

python 追蹤except資訊方式

看下面這個函式

def test():
 sum = 3/0
 
if __name__ == '__main__':
 test()

除0肯定是不對的,會引發一個except,內容如下:

File "E:\Src\dongsheng\TestPython\testtrace_back.py",line 23,in <module>
test()
File "E:\Src\dongsheng\TestPython\testtrace_back.py",line 19,in test
sum = 3/0
ZeroDivisionError: integer division or modulo by zero

上面的提示,是在IDE中執行時出現的,實際在線上執行指令碼時,一般會用nohup 方式啟動,輸出內容會寫入到nohup.out檔案中,但這個檔案裡的內容可能非常多,很雜亂,不利於異常的排查。

python 提供了traceback ,可以完美的輸出except發生時的資訊,就和上面的內容一樣,而且可以輸入到指定的檔案之中,所以,不妨寫一個裝飾器,修飾那些需要監督的函式,當他們發生異常時,記錄下有關異常的資訊。

#coding=utf-8
from functools import wraps
import traceback
 
def except_trace(filename):
 def decorate(func):
  @wraps(func)
  def wrapper(*args,**kwargs):
   try:
    func(*args,**kwargs)
   except:
    fp = open(filename,'w')
    traceback.print_exc(file=fp)
    fp.close()
  return wrapper
 return decorate
@except_trace('1.txt')
def test():
 sum = 3/0
 
if __name__ == '__main__':
 test()

這一次,發生異常後,有關異常的資訊會輸入到1.txt檔案中,這個檔案中只包含異常的資訊,方便檢視。

補充知識:Python 的 except 怪癖

讓我來展示一下我最喜歡的 Python 怪癖。你希望這段 Python 程式碼做什麼?

如果你是從另一種程式語言過來學習 Python 的,你可能希望except子句引入巢狀範圍,因此在子句中賦值給 e 不會影響外部作用域中已有的 e 變數。然而,在 Python 中,控制結構通常不引入巢狀作用域(列表推導是一個例外),所以如果你有更多的 Python 經驗,你可能會期望它列印一個ZeroDivisionError例項。

實際上,在標準 CPython 實現中,它什麼也不列印;同時,最後一行將引發一個NameError。這是一個 bug 嗎?事實上,這是故意的。如果檢視 except 子句生成的位元組碼,可以看到:

當控制流退出except塊時,Python 將從作用域中刪除該名稱。為什麼?因為異常持有對當前棧幀的引用,該棧幀包含作用域內的所有內容。由於Python主要是通過引用計數來管理記憶體主體的,這意味著當前作用域內的任何內容都不會被釋放,直到下一輪垃圾收集執行 (如果有的話)。目前的行為是記憶體使用、易於實現和語言整潔之間的折衷。它有點缺點,但我認為它體現了我喜歡Python的一點:不讓純粹性妨礙實用性。

但這隻解釋了DELETE_NAME指令。為什麼 CPython 把e設為None,即便隨後立即就刪除了這個變數?好吧,設想你和 CPython 團隊有相同的想法,並且決定在 except 塊的末尾清理異常引用:

在except塊的末尾,CPython 將嘗試刪除你已經刪除的名字e!為了解決這個問題,CPython 在刪除e之前賦值e = None,以確保e存在。

以上這篇python 追蹤except資訊方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。