Python:如何消除库代码中的堆栈追踪?

11 投票
5 回答
2140 浏览
提问于 2025-04-15 21:28

当我从标准库中遇到运行时异常时,几乎总是我自己代码的问题,而不是库里的问题。有没有办法截断异常的堆栈跟踪,这样就不会显示库包的内部信息呢?

举个例子,我希望得到这样的结果:

Traceback (most recent call last):
  File "./lmd3-mkhead.py", line 71, in <module>
    main()
  File "./lmd3-mkhead.py", line 66, in main
    create()
  File "./lmd3-mkhead.py", line 41, in create
    headver1[depotFile]=rev
TypeError: Data values must be of type string or None.

而不是这样的:

Traceback (most recent call last):
  File "./lmd3-mkhead.py", line 71, in <module>
    main()
  File "./lmd3-mkhead.py", line 66, in main
    create()
  File "./lmd3-mkhead.py", line 41, in create
    headver1[depotFile]=rev
  File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/__init__.py", line 276, in __setitem__
    _DeadlockWrap(wrapF)  # self.db[key] = value
  File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/dbutils.py", line 68, in DeadlockWrap
    return function(*_args, **_kwargs)
  File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/__init__.py", line 275, in wrapF
    self.db[key] = value
TypeError: Data values must be of type string or None.

更新:添加了一个 答案,感谢Alex的提示。

5 个回答

1

你可能需要用到 Traceback库。这里有一个例子,可能对你有帮助:

import traceback

try:
    your_main()
except:
    lines = traceback.format_exc()
    print lines[:lines.find('File "/usr')]

(当然,如果在库外发生了异常,这个方法就不管用了,而且可能不完全符合你的需求,但这是一种使用Traceback库的方法)

12

Python的标准库里有一个叫做traceback的模块,它可以让你在出现错误时以你喜欢的方式显示错误信息。你可以在try/except语句的except部分使用这个功能,或者在你设置的一个函数中使用这个功能,这个函数叫做sys.excepthook,当错误一直传播到最外层时会被调用;文档中是这么说的:

在交互式会话中,这个过程发生在控制权返回到提示符之前;在Python程序中,这个过程发生在程序退出之前。你可以通过给sys.excepthook赋值一个其他的三参数函数来定制这种顶层异常的处理方式。

这里有一个简单的例子:

>>> import sys
>>> import traceback
>>> def f(n):
...   if n<=0: raise ZeroDivisionError
...   f(n-1)
... 
>>> def excepthook(type, value, tb):
...   traceback.print_exception(type, value, tb, 3)
... 
>>> sys.excepthook = excepthook
>>> f(8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f
  File "<stdin>", line 3, in f
ZeroDivisionError

如你所见,不需要使用try/except,你就可以轻松限制错误信息的显示层级,比如只显示前面三层——尽管我们知道在错误发生时实际上有9层嵌套。

如果你想要的功能比简单限制层级更复杂,那你需要调用traceback.format_exception,这个函数会给你一个包含多行信息的列表,而不是直接打印出来。然后你可以从这个列表中“修剪”掉那些你不想在错误信息中看到的模块的行,最后把剩下的行输出(通常是输出到sys.stderr,不过随你喜欢!)。

5

感谢Alex的提示,这里是代码:

def trimmedexceptions(type, value, tb, pylibdir=None, lev=None):
    """trim system packages from the exception printout"""
    if pylibdir is None:
        import traceback, distutils.sysconfig
        pylibdir = distutils.sysconfig.get_python_lib(1,1)
        nlev = trimmedexceptions(type, value, tb, pylibdir, 0)
        traceback.print_exception(type, value, tb, nlev)
    else:
        fn = tb.tb_frame.f_code.co_filename
        if tb.tb_next is None or fn.startswith(pylibdir):
            return lev
        else:
            return trimmedexceptions(type, value, tb.tb_next, pylibdir, lev+1)

import sys
sys.excepthook=trimmedexceptions

# --- test code ---

def f1(): f2()
def f2(): f3()
def f3():
    import xmlrpclib
    proxy = xmlrpclib.ServerProxy('http://nosuchserver')
    proxy.f()

f1()

这段代码会产生这样的堆栈跟踪信息:

Traceback (most recent call last):
  File "./tsttraceback.py", line 47, in <module>
    f1()
  File "./tsttraceback.py", line 40, in f1
    def f1(): f2()
  File "./tsttraceback.py", line 41, in f2
    def f2(): f3()
  File "./tsttraceback.py", line 45, in f3
    proxy.f()
gaierror: [Errno -2] Name or service not known

撰写回答