由SyntaxError
函数引发的TypeError
s(和compile()
s)似乎 包含在{{1}返回的堆栈跟踪中},但 使用sys.exc_info()
打印为格式化输出的一部分。
例如,给定以下代码(其中traceback.print_exc
是包含带有行filename
的Python代码的文件的名称):
$ flagrant syntax error
我得到以下输出(其中import sys
from traceback import extract_tb
try:
with open(filename) as f:
code = compile(f.read(), filename, "exec")
except:
print "using sys.exc_info:"
tb_list = extract_tb(sys.exc_info()[2])
for f in tb_list:
print f
print "using traceback.print_exc:"
from traceback import print_exc
print_exc()
是包含上述代码的脚本的名称):
<scriptname>
我有三个问题:
using sys.exc_info:
('<scriptname>', 6, 'exec_file', 'code = compile(f.read(), filename, "exec")')
using traceback.print_exc:
Traceback (most recent call last):
File "<scriptname>", line 6, in exec_file
code = compile(f.read(), filename, "exec")
File "<filename>", line 3
$ flagrant syntax error
^
SyntaxError: invalid syntax
的追溯不包括生成sys.exc_info()
的帧?SyntaxError
如何获取缺少的相框信息?traceback.print_exc
?是否需要使用SyntaxError
和SyntaxError
异常对象本身手动构建最后一个列表元素(即表示filename
发生位置的堆栈帧中的信息)?对于上下文,这是我试图获得完整的堆栈跟踪提取的用例。
我有一个基本上通过SyntaxError
包含用户编写的Python代码的文件来实现DSL的程序。 (无论这是否是一个很好的DSL实现策略,我或多或少地坚持使用它。)当遇到用户代码中的错误时,我会(在某些情况下)像解释器一样保存以后的错误,而不是呕吐堆栈跟踪和死亡。所以我有一个专门用来存储这些信息的exec
课程。这是该类的ScriptExcInfo
方法的一个(稍微编辑过的版本),上面提到了一个相当丑陋的解决方法:
__init__
请注意,&#34;相当难看,&#34;我的意思是这个解决方法将应该是单参数的4行def __init__(self, scriptpath, add_frame):
self.exc, tb = sys.exc_info()[1:]
self.tb_list = traceback.extract_tb(tb)
if add_frame:
# Note: I'm pretty sure that the names of the linenumber and
# message attributes are undocumented, and I don't think there's
# actually a good way to access them.
if isinstance(exc, TypeError):
lineno = -1
text = exc.message
else:
lineno = exc.lineno
text = exc.text
# '?' is used as the function name since there's no function context
# in which the SyntaxError or TypeError can occur.
self.tb_list.append((scriptpath, lineno, '?', text))
else:
# Pop off the frames related to this `exec` infrastructure.
# Note that there's no straightforward way to remove the unwanted
# frames for the above case where the desired frame was explicitly
# constructed and appended to tb_list, and in fact the resulting
# list is out of order (!!!!).
while scriptpath != self.tb_list[-1][0]:
self.tb_list.pop()
函数转换为需要两个参数并占用13行。
答案 0 :(得分:8)
两种方法之间的唯一差异是print_exc()
打印格式化的异常。对于SyntaxError
,其中包括格式化该异常中的信息,其中包括导致问题的实际行。
对于回溯本身,print_exc()
使用sys.exc_info()[2]
,您使用的信息与产生回溯的信息相同。换句话说,它没有获得比你已经做的更多的信息,但你忽略了异常信息本身:
>>> import traceback
>>> try:
... compile('Hmmm, nope!', '<stdin>', 'exec')
... except SyntaxError as e:
... print ''.join(traceback.format_exception_only(type(e), e))
...
File "<stdin>", line 1
Hmmm, nope!
^
SyntaxError: invalid syntax
此处traceback.format_exception_only()
是traceback.print_exc()
用于格式化异常值的未记录函数。所有信息都可供您在异常情况下提取:
>>> dir(e)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', 'args', 'filename', 'lineno', 'message', 'msg', 'offset', 'print_file_and_line', 'text']
>>> e.args
('invalid syntax', ('<stdin>', 1, 11, 'Hmmm, nope!\n'))
>>> e.filename, e.lineno, e.offset, e.text
('<stdin>', 1, 11, 'Hmmm, nope!\n')
另请参阅traceback.print_exception()
的文档:
(3)如果类型是
SyntaxError
并且值具有适当的格式,则会打印出现语法错误的行,并使用插入符号指示错误的大致位置。
此类的实例具有属性
filename
,lineno
,offset
和text
,以便于访问详细信息。异常实例的str()
仅返回消息。
回溯中不包含语法错误的行只是逻辑;无法执行具有语法错误的代码,因此不会为其创建任何执行帧。而compile()
函数抛出异常,这是最底层的执行框架。
因此,你被困在丑陋的&#39;办法;这是处理SyntaxError
例外的正确方法。但是,属性已记录。
请注意,exception.message
通常设置为exception.args[0]
,而str(exception)
通常会为您提供相同的消息(如果args
更长str(exception.args)
相反,虽然某些例外类型提供的自定义__str__
通常只会为您提供exception.args[0]
)。