从异常拦截的被调用者获取命名空间

时间:2013-06-01 13:58:30

标签: python

我想拦截异常并在执行Python代码时执行一些报告。主要是我想在发生异常时导出代码的命名空间。

我能做的是:

我有文件test.py会引发异常:

for i in range(10):
    if i > 5:
        j
    else:
        i

文件check.py将拦截异常并在测试脚本作为参数传递时启动调试器:

import sys, pdb

try:
    __import__(sys.argv[1])
except Exception as e:
    pdb.post_mortem(sys.exc_info()[2])

那太好了。

此外,我可以使用inspect模块找到发生异常的被调用者中的帧:

import sys, inspect

try:
    __import__(sys.argv[1])
except Exception as e:
    callee_frame_tuple = inspect.trace()[1]
    print callee_frame_tuple

输出:

(<frame object at 0x00C9B260>, 'C:\\Temp\\test.py', 3, '<module>', ['        j\n'], 0)

并使用它来获取有关getargvalues()的框架的信息:

import sys, inspect

try:
    __import__(sys.argv[1])
except Exception as e:
    callee_frame_tuple = inspect.trace()[1]
    inspect.getargvalues(callee_named_tuple[0])[3]['__builtins__']['locals']()

输出:

{'__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__file__': 'C:\\Temp\\check.py',
 '__name__': '__main__',
 '__package__': None,
 'e': NameError("name 'j' is not defined",),
 'inspect': <module 'inspect' from 'C:\Python27\lib\inspect.pyc'>,
 'sys': <module 'sys' (built-in)>}

所以我得到了check.py的本地人而不是被叫者test.py的本地人,尽管我把它的帧参考用作getargvalues()参数。

有谁知道如何获得被调用者名称空间?

1 个答案:

答案 0 :(得分:1)

从Python打印的格式化回溯中不清楚,但由于您使用的是__import__,因此您实际上会获得两个单独的traceback个对象。您可以像这样访问第二个......

import sys
from pprint import pprint

try:
    __import__(sys.argv[1])
except Exception as e:
    my_traceback = sys.exc_info()[2]

# Print locals for my stack frame
#pprint(my_traceback.tb_frame.f_locals)

# Print locals for other stack frame
other_traceback = my_traceback.tb_next
pprint(other_traceback.tb_frame.f_locals)

有关Python文档section 3.2tracebackframe个对象的更多信息。


<强>更新

  

这与inspect.getargvalues(callee_named_tuple[0])的对象相同   上面,所以我不知道这实际上是被叫当地人,而我   深入研究。

你是对的。我对inspect模块并不熟悉 - 我倾向于直接访问traceback属性。

  

我原以为我可以找到i变量所在的命名空间字典   值6然后发生异常,这样我得到i=None。是   有没有办法获得被调用者的命名空间?

我也注意到了。使用__import__似乎有点奇怪,因为它在使用execfile()时工作正常。以下脚本......

import sys

try:
    execfile(sys.argv[1])
except Exception as e:
    the_value_of_i = sys.exc_info()[2].tb_next.tb_frame.f_locals['i']
    print 'The value of "i" was "%r"' % the_value_of_i

... ...产量

The value of "i" was "6"