exec中字符串的python回溯?

exec中字符串的python回溯?,python,traceback,Python,Traceback,我有一个存储在字符串中的函数,看起来像这样: func_str = "def <func_name> ..." 现在这个函数可能有一个异常,我想知道是哪一行导致了字符串中的异常。在解释器中运行它会给我一条错误消息,这正是我想要的: File "<string>", line 6, in <func_name> TypeError: can only concatenate tuple (not "int") to tuple 文件“”,第6行,在 Ty

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

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

  File "<string>", line 6, in <func_name>
TypeError: can only concatenate tuple (not "int") to tuple
文件“”,第6行,在
TypeError:只能将元组(而不是“int”)连接到元组
这告诉我字符串中的第6行导致了问题

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


谢谢

在这种情况下,我想您应该使用
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
导入回溯 >>>尝试:评估(“1/0”) ... 除了:打印“得到异常:”,traceback.format_exc() ... 获取异常:回溯(最近一次调用last): 文件“”,第1行,在 文件“”,第1行,在 ZeroDivisionError:整数除法或模零除法
好吧,这感觉又脏又恶心,但给你

sys.exc_info()[2].tb_next.tb_lineno+frameinfo.lineno

Lineno必须直接位于字符串化代码的上方才能求值,或者如果代码是从脚本的开头开始的,那么显然这是不必要的

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
如果您只希望此字符串化源使用“lineno”,则

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
输出:


但这似乎是失败的,因为结尾有太多的新行(因此您至少需要剥离()func_str)

感谢这些答案,它们非常有用

我认为我所缺少的基本上是一种“进入”回溯堆栈的方法,因为我在外部异常上停止,而不是进入故障的绝对“根”

这对我来说是个好办法:

def go_deeper(deeep):
  if deeep.tb_next == None:
    return deeep.tb_lineno
  else:
    return go_deeper(deeep.tb_next)

这将导致最深层的异常,这基本上是我所需要的。

如果我的字符串是从外部传递的,而不是在我编写脚本时被知道的,那该怎么办?嗯,很有趣,比如通过套接字发送?然后你可以让疯狂的事情发生:)并在你要执行的字符串之前附加
frameinfo=getframeinfo(currentframe())
。我们可以把它想象成一个远程调用,有人给你发送一个要执行的字符串。不管怎样,我想我用tb_next解决了它,然后转到下一层。谢谢你花时间回答!exec应该在本地范围内定义一个函数,然后我使用“locals()[func_name](inp)执行该函数
Fails at: 27
Inside: 11
def go_deeper(deeep):
  if deeep.tb_next == None:
    return deeep.tb_lineno
  else:
    return go_deeper(deeep.tb_next)