簡體   English   中英

異常堆棧跟蹤中的 locals() 和 globals() (Python)

[英]locals() and globals() in stack trace on exception (Python)

雖然堆棧跟蹤在 Python 中很有用,但問題根源的數據通常會丟失——有沒有辦法確保至少將 locals()(可能還有 globals())添加到打印的堆棧跟蹤中?

您可以安裝自己的異常鈎子並從那里輸出您需要的內容:

import sys, traceback

def excepthook(type, value, tb):
    traceback.print_exception(type, value, tb)

    while tb.tb_next:
        tb = tb.tb_next

    print >>sys.stderr, 'Locals:',  tb.tb_frame.f_locals
    print >>sys.stderr, 'Globals:', tb.tb_frame.f_globals

sys.excepthook = excepthook

def x():
    y()

def y():
    foo = 1
    bar = 0

    foo/bar

x()

要在回溯中打印每個幀的變量,請將上述循環更改為

    while tb:
        print >>sys.stderr, 'Locals:',  tb.tb_frame.f_locals
        print >>sys.stderr, 'Globals:', tb.tb_frame.f_globals
        tb = tb.tb_next

這是一盒潘多拉。 打印形式的值可能非常大; 在堆棧跟蹤中打印所有局部變量很容易由於錯誤輸出而導致新問題。 這就是為什么這在 Python 中一般沒有實現。

但是,在小示例中,即如果您知道您的值不會太大而無法正確打印,您可以自己跟蹤回溯:

import sys
import traceback

def c():
  clocal = 1001
  raise Exception("foo")

def b():
  blocal = 23
  c()

def a():
  alocal = 42
  b()

try:
  a()
except Exception:
  frame = sys.exc_info()[2]
  formattedTb = traceback.format_tb(frame)    
  frame = frame.tb_next
  while frame:
    print formattedTb.pop(0), '\t', frame.tb_frame.f_locals
    frame = frame.tb_next

輸出將是這樣的:

  File "/home/alfe/tmp/stacktracelocals.py", line 19, in <module>
    a()
        {'alocal': 42}
  File "/home/alfe/tmp/stacktracelocals.py", line 16, in a
    b()
        {'blocal': 23}
  File "/home/alfe/tmp/stacktracelocals.py", line 12, in b
    c()
        {'clocal': 1001}

當然,您可以按照他的回答中建議的 thg435 安裝您自己的 except 鈎子。

如果您還不知道這一點,請使用 pdb post-mortem 功能:

x = 3.0
y = 0.0
print x/y
def div(a, b):
    return a / b
print div(x,y)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-3-d03977de5fc3> in div(a, b)
      1 def div(a, b):
----> 2     return a / b

ZeroDivisionError: float division

import pdb
pdb.pm()
> <ipython-input-3-148da0dcdc9e>(2)div()
      0     return a/b

ipdb> l
      1 def div(a,b):
----> 2     return a/b

ipdb> a
3.0
ipdb> b
0.0

等。

當然,在某些情況下,您確實需要打印件。 您最好檢測代碼(通過 try/except)以打印出圍繞您正在調試的特定奇怪異常的額外信息,而不是將其用於所有內容,恕我直言。

嘗試帶有變量的回溯包。

用法:

from traceback_with_variables import traceback_with_variables

def main():
    ...
    with traceback_with_variables():
        ...your code...

例外情況:

Traceback with variables (most recent call last):
  File "./temp.py", line 7, in main
    return get_avg_ratio([h1, w1], [h2, w2])
      sizes_str = '300 200 300 0'
      h1 = 300
      w1 = 200
      h2 = 300
      w2 = 0
  File "./temp.py", line 10, in get_avg_ratio
    return mean([get_ratio(h, w) for h, w in [size1, size2]])
      size1 = [300, 200]
      size2 = [300, 0]
  File "./temp.py", line 10, in <listcomp>
    return mean([get_ratio(h, w) for h, w in [size1, size2]])
      .0 = <tuple_iterator object at 0x7ff61e35b820>
      h = 300
      w = 0
  File "./temp.py", line 13, in get_ratio
    return height / width
      height = 300
      width = 0
builtins.ZeroDivisionError: division by zero

安裝:

pip install traceback-with-variables

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM