2

在 python 中,您可以使用 exec() 来更快地执行 compile() 字符串。但是一旦我使用它,当 exec 中发生异常时,我们就会丢失信息。

例如,这是一个调用未知方法的代码片段(用于演示目的):

code = 'my_unknown_method()'
bytecode = compile(code, '<string>', 'exec')

后来,我在那个字节码上调用 exec :

exec bytecode

显示的回溯是:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    exec bytecode
  File "<string>", line 1, in <module>
NameError: name 'my_unknown_method' is not defined   

“exec()”框架现在是模糊的。我想要一个更好的例外,例如:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    exec "my_unknown_method()"
  File "<string>", line 1, in <module>
NameError: name 'my_unknown_method' is not defined   

有什么想法吗 ?

笔记:

  • 我不想使用 compile 的第二个参数(文件名)
  • 我已经测试过在框架上使用检查和修改 f_code,但它是只读属性。

编辑:在查看更多 sys.excepthook 之后,我在 python 源代码/traceback.c 中看到,当 python 想要显示行内容时,如果找到,它们是 fopen() 直接文件。根本没有可用的钩子来显示我们自己的内容。唯一的方法是在磁盘上创建真正的假文件名?任何人 ?

EDIT2:我检查了一些 jinja2 调试代码,他们也在重写回溯,但不是为了内容。除了钩子,我需要定制吗?我对它的担心是因为它不在回溯本身中,如果用户/模块/任何异常,回溯将不包含有价值的信息。

4

3 回答 3

4

你应该看看Armin Ronacher 的这个演讲。他是 Jinja2 的作者,在这次演讲中他解释了他如何在 Jinja2 中操作堆栈跟踪。如果我没记错的话,他正在使用 ctypes 来操作 Python 的 C 级别的数据结构。顺便说一句,在我看来,这次演讲是整个 Europython 2011 中最好的演讲。

于 2011-11-25T22:52:38.563 回答
2

经过深入搜索,这是不可能的,CPython 正在使用自己的 API 来确定文件的位置等,并且无法在纯 Python 中对其进行修补。

于 2012-02-08T12:24:38.150 回答
0

像这样的东西怎么样:

import sys
def mkexec(code_str):
    bc = compile(code, '<string>', 'exec')
    def run():
        try:
            exec bc
        except: # Yes I know a bare except
            t, v, tb = sys.exc_info()
            raise MyUsefullException("%s raised %s" % (code_str, v))
    return run

exe = mkexec("some_unknown_something()")
exe()
于 2011-11-18T11:36:56.070 回答