我有一个存储在字符串中的函数,它看起来像这样:
"
我正在使用" exec"进行评估。并在输入上使用它如下:
func_str = "def <func_name> ..."
现在这个函数可能有异常,我想知道哪一行在字符串中引起了它。在解释器中运行它会给出一条错误消息,这正是我想要的:
exec func_str in locals()
locals()[func_name](inp)
这告诉我字符串中的第6行导致问题。
有没有办法以编程方式捕获此内容?我已经查看了类似的解决方案,但是他们没有解决来自在本地范围内执行的字符串的异常。尝试使用traceback模块时,我只获得了调用exec的外部函数的行号。
感谢
答案 0 :(得分:3)
嗯,这感到肮脏和恶心,但在这里你去。
sys.exc_info()[2].tb_next.tb_lineno + frameinfo.lineno
Lineno必须直接在你的字符串化代码上面进行eval,或者如果代码在脚本开头处开始 - 显然没有必要。
import sys
from inspect import currentframe, getframeinfo
frameinfo = getframeinfo(currentframe())
func_str = """
def func_name(param):
d = []
u = 1
pass
a = ''
pass
print a + param
print "hi"
print "ho"
"""
exec func_str in locals()
inp = 1
try:
locals()["func_name"](inp)
except Exception as e:
print "Fails at:", sys.exc_info()[2].tb_next.tb_lineno + frameinfo.lineno
print "Inside:", len(func_str.split("\n")) - frameinfo.lineno
输出
Fails at: 12
Inside: 7
如果你想要&#34; lineno&#34;仅适用于此字符串化源,
len(func_str.split("\n") - frameinfo.lineno
我不知道你是自己决定使用这个架构还是被迫使用它,但我感到很抱歉:)
编辑:
如果您远程接收字符串
import sys
from inspect import currentframe, getframeinfo
some_item = "frameinfo = getframeinfo(currentframe())"
pass
random_items_here = 1
func_str = """
line_no = 2
lineno = 3
a_number = 0
def func_name(param):
d = []
u = 1
pass
a = ''
pass
print a + param
print "hi"
print "ho"
"""
exec some_item + "\n" + func_str in locals()
inp = 1
try:
locals()["func_name"](inp)
except Exception as e:
print "Fails at:", sys.exc_info()[2].tb_lineno
print "Inside:", len(func_str.split("\n")) - 2 - frameinfo.lineno
出:
Fails at: 27
Inside: 11
但是这似乎在最后没有超过新行(所以你至少需要剥离()func_str)
答案 1 :(得分:1)
我认为在这种情况下你会想要使用eval
。 exec
不返回任何内容:
>>> import traceback
>>> try: eval("1/0")
... except: print "Got exception:", traceback.format_exc()
...
Got exception: Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
答案 2 :(得分:0)
感谢答案,他们非常乐于助人。
我认为我所缺少的本质上是一种“进入”回溯堆栈的方法,因为我停止了外部异常,而不是去了失败的绝对“根”
这对我有用:
def go_deeper(deeep):
if deeep.tb_next == None:
return deeep.tb_lineno
else:
return go_deeper(deeep.tb_next)
这将导致异常原因的最深层,这基本上就是我所需要的。