为什么无法在Python中对错误的Traceback进行pickle?

28 投票
3 回答
8784 浏览
提问于 2025-04-16 18:21

我已经找到了一种解决办法,但还是想知道这个问题的答案。

3 个回答

1

我猜你是想保存完整的调用上下文,包括错误追踪信息全局变量和每个框架的局部变量

这样做非常有用,可以帮助你比较同一个函数在两种不同调用上下文中的表现,或者用来制作一些高级工具,处理、展示或比较这些错误追踪信息。

不过问题是,pickl这个工具并不知道怎么把所有类型的对象序列化,这些对象可能出现在局部变量全局变量中。

我想你可以自己创建一个对象来保存这些信息,过滤掉那些不能被pickl处理的对象。下面的代码可以作为基础:

import sys, traceback

def print_exc_plus():
    """
    Print the usual traceback information, followed by a listing of all the
    local variables in each frame.
    """
    tb = sys.exc_info()[2]
    while 1:
        if not tb.tb_next:
            break
        tb = tb.tb_next
    stack = []
    f = tb.tb_frame
    while f:
        stack.append(f)
        f = f.f_back
    stack.reverse()
    traceback.print_exc()
    print "Locals by frame, innermost last"
    for frame in stack:
        print
        print "Frame %s in %s at line %s" % (frame.f_code.co_name,
                                             frame.f_code.co_filename,
                                             frame.f_lineno)
        for key, value in frame.f_locals.items():
            print "\t%20s = " % key,
            #We have to be careful not to cause a new error in our error
            #printer! Calling str() on an unknown object could cause an
            #error we don't want.
            try:                   
                print value
            except:
                print "<ERROR WHILE PRINTING VALUE>"

不过与其打印这些对象,你可以把它们添加到一个列表中,用你自己的可序列化表示方式(比如jsonyml格式可能更好)。

也许你想加载这些调用上下文,以便在不运行复杂工作流程的情况下重现同样的情况。我不确定这是否可行(因为内存引用的问题),但如果可以的话,你需要从你的格式中反序列化这些信息。

4

你可以使用 tblib 这个库。

    try:
        1 / 0
    except Exception as e:
         raise Exception("foo") from e
except Exception as e:
    s = pickle.dumps(e)
raise pickle.loads(s)
24

错误追踪信息记录了当前线程中每个被调用的函数或方法的状态,从最上面的那一层开始,一直到出现错误的地方。每一层的状态还包含了当时所有局部变量和全局变量的信息。

因为没有办法让pickle知道哪些信息需要保存,哪些可以忽略,所以如果你试图把错误追踪信息保存下来,就相当于在保存整个应用程序的实时快照:在pickle运行的时候,其他线程可能会在修改共享变量的值。

一个解决办法是创建一个可以被pickle处理的对象,来遍历错误追踪信息,只提取你需要保存的部分。

撰写回答