【问题标题】:Why can't I pickle an error's Traceback in Python?为什么我不能在 Python 中腌制错误的 Traceback?
【发布时间】:2011-05-26 00:20:11
【问题描述】:

我已经找到了解决方法,但仍然想知道答案。

【问题讨论】:

  • 那么你应该解释你到底想要做什么。您可以使用 traceback.format_exec() 将您的回溯转换为字符串。字符串非常容易腌制。
  • 我不一定在抱怨,但我对为什么这被完全否决感兴趣。在 1) 缺乏研究、2) 不清楚或 3) 没有用的情况下,我想如果必须,我会选择 (1),但这是否意味着我应该列出所有 没有的 Google 搜索结果和书籍't 包含我想要的答案?
  • @Trindaz 我没有投反对票,但如果我不得不猜测三个 -1 的出处,我会说这是由于您的问题缺乏细节。你为什么要腌制回溯?您找到的解决方法是什么?
  • 你找到了什么解决方法?
  • 有一个名为eliot 的库在为您记录回溯方面做得非常好。以下是 eliot 进行回溯日志记录的方式:github.com/itamarst/eliot/blob/master/eliot/_traceback.py#L82

标签: python pickle traceback


【解决方案1】:

回溯保存对在当前线程上调用的每个函数/方法的堆栈帧的引用,从最顶层帧一直到引发错误的点。每个堆栈帧还保存对调用堆栈中的每个函数时有效的局部和全局变量的引用。

由于 pickle 无法知道要序列化什么以及忽略什么,如果您能够 pickle 回溯,您最终会腌制整个应用程序状态的移动快照:当 pickle 运行时,其他线程可能正在修改共享变量的值。

一种解决方案是创建一个picklable对象来遍历回溯并仅提取您需要保存的信息。

【讨论】:

  • 感谢您的超清晰答案.. 完全有道理。我在网络上透明地传送 LogRecord 的梦想破灭了,但现在我明白为什么它不能完成了……
【解决方案2】:

您可以使用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)

【讨论】:

    【解决方案3】:

    我猜你有兴趣保存完整的调用上下文(traceback + globals + locals 每帧)。

    这对于确定同一函数在两个不同调用上下文中的行为差异,或者构建您自己的高级工具来处理、显示或比较这些回溯非常有用。

    问题在于 pickl 不知道如何序列化所有可能在 localsglobals 中的对象类型。

    我猜你可以构建自己的对象并保存它,过滤掉所有不是 picklabe 的对象。这段代码可以作为基础:

    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 格式可能更好),而不是打印对象。

    也许您想加载所有这些调用上下文,以便为您的函数重现相同的情况,而无需运行生成它的复杂工作流程。我不知道这是否可以做到(因为内存引用),但在这种情况下,你需要从你的格式中反序列化它。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-09
    • 2016-02-21
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 2016-06-03
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多