当代码是字符串中的 exec() 时,如何以编程方式获取回溯的行号?

Eva*_* Pu 6 python traceback

我有一个存储在字符串中的函数,它看起来像这样:

func_str = "def <func_name> ..."
Run Code Online (Sandbox Code Playgroud)

我正在使用“exec”评估它并在输入上使用它,如下所示:

exec func_str in locals()
locals()[func_name](inp)
Run Code Online (Sandbox Code Playgroud)

现在这个函数可能有一个异常,我想知道字符串中哪一行导致了它。在解释器中运行它会给出一条错误消息,这正是我想要的:

  File "<string>", line 6, in <func_name>
TypeError: can only concatenate tuple (not "int") to tuple
Run Code Online (Sandbox Code Playgroud)

这告诉我字符串中的第六行导致了问题。

有什么方法可以以编程方式捕获这个吗?我看过类似的解决方案,但它们没有解决来自在本地范围内执行的字符串的异常。当尝试使用回溯模块时,我只获得了调用 exec 的外部函数的行号。

谢谢

Jus*_*tMe 5

好吧,这感觉又脏又恶心,但你走了。

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
Run Code Online (Sandbox Code Playgroud)

输出

Fails at: 12
Inside: 7
Run Code Online (Sandbox Code Playgroud)

如果您只想将此字符串化源使用“lineno”,那么

len(func_str.split("\n") - frameinfo.lineno
Run Code Online (Sandbox Code Playgroud)

我不知道你是自己决定这个架构还是被迫的,但我感到抱歉:)

编辑:

如果您远程接收字符串

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
Run Code Online (Sandbox Code Playgroud)

出去:

Fails at: 27
Inside: 11
Run Code Online (Sandbox Code Playgroud)

但这似乎在最后出现过多的新行而失败(因此您至少需要 strip() func_str )


Mat*_*son 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
Run Code Online (Sandbox Code Playgroud)