简体   繁体   English

为什么我不能在 Python 中腌制错误的 Traceback?

[英]Why can't I pickle an error's Traceback in Python?

I've since found a work around, but still want to know the answer.从那以后,我找到了解决方法,但仍然想知道答案。

The traceback holds references to the stack frames of each function/method that was called on the current thread, from the topmost-frame on down to the point where the error was raised.回溯保存对在当前线程上调用的每个函数/方法的堆栈帧的引用,从最顶层帧一直到引发错误的点。 Each stack frame also holds references to the local and global variables in effect at the time each function in the stack was called.每个堆栈帧还保存对调用堆栈中每个 function 时有效的局部和全局变量的引用。

Since there is no way for pickle to know what to serialize and what to ignore, if you were able to pickle a traceback you'd end up pickling a moving snapshot of the entire application state: as pickle runs, other threads may be modifying the values of shared variables.由于 pickle 无法知道要序列化什么和忽略什么,如果您能够腌制回溯,您最终会腌制整个应用程序 state 的移动快照:当 pickle 运行时,其他线程可能正在修改共享变量的值。

One solution is to create a picklable object to walk the traceback and extract only the information you need to save.一种解决方案是创建一个可提取的 object 来回溯并仅提取您需要保存的信息。

You can use tblib您可以使用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)

I guess you are interested in saving the complete call context ( traceback + globals + locals of each frame).我猜您有兴趣保存完整的调用上下文(每帧的回溯+全局变量+局部变量)。

That would be very useful to determine a difference of behavior of the same function in two different call contexts, or to build your own advanced tools to process, show or compare those tracebacks.这对于确定相同 function 在两个不同调用上下文中的行为差异,或者构建您自己的高级工具来处理、显示或比较这些回溯非常有用。

The problem is that pickl doesn't know how to serialize all type of objects that could be in the locals or globals .问题是pickl不知道如何序列化可能在localsglobals中的所有类型的对象。

I guess you can build your own object and save it, filtering out all those objects that are not picklabe .我想您可以构建自己的 object 并保存它,过滤掉所有那些不是picklabe的对象。 This code can serve as basis:此代码可以作为基础:

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>"

but instead of printing the objects you can add them to a list with your own pickable representation ( a json or yml format might be better).但不是打印对象,您可以使用自己的可选择表示形式将它们添加到列表中( jsonyml格式可能更好)。

Maybe you want to load all this call context in order to reproduce the same situation for your function without run the complicated workflow that generate it.也许您想加载所有这些调用上下文,以便为您的 function 重现相同的情况,而无需运行生成它的复杂工作流程。 I don't know if this can be done (because of memory references), but in that case you would need to de-serialize it from your format.我不知道这是否可以完成(因为 memory 引用),但在这种情况下,您需要从您的格式中反序列化它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM