为什么无法在Python中对错误的Traceback进行pickle?
我已经找到了一种解决办法,但还是想知道这个问题的答案。
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>"
不过与其打印这些对象,你可以把它们添加到一个列表中,用你自己的可序列化表示方式(比如json或yml格式可能更好)。
也许你想加载这些调用上下文,以便在不运行复杂工作流程的情况下重现同样的情况。我不确定这是否可行(因为内存引用的问题),但如果可以的话,你需要从你的格式中反序列化这些信息。
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处理的对象,来遍历错误追踪信息,只提取你需要保存的部分。