python - 文件 "<string>"回溯和行预览

标签 python python-3.x traceback

我正在通过 exec 创建几个函数,这可能会出错。但是,当 Python 出错时,它不会显示发生错误的行。

例如使用:

fn_str = '''\
def fn():
    raise Exception()
'''

globs = {}
exec(fn_str, globs)
fn = globs['fn']

fn()

给我们输出:

Traceback (most recent call last):
  File "...", line 10, in <module>
    fn()
  File "<string>", line 2, in fn
Exception
<小时/>

但是,如果我们不使用 eval。然后我们得到程序出错的行:

def fn():
    raise Exception()

fn()
Traceback (most recent call last):
  File "...", line 4, in <module>
    fn()
  File "...", line 2, in fn
    raise Exception()
Exception
<小时/>

我已经研究过使用__traceback__,但是我找不到添加到"file"行下的回溯的方法。所以我能得到的最好的结果是:

fn_str = '''\
def fn():
    try:
        raise Exception()
    except BaseException as e:
        tb = e.__traceback__
        if 1 <= tb.tb_lineno <= len(fn_lines):
            e.args = ((e.args[0] if e.args else '') + ' - ' + fn_lines[tb.tb_lineno - 1].strip(),)
        raise
'''

globs = {'fn_lines': fn_str.split('\n')}
exec(fn_str, globs)
fn = globs['fn']

fn()
Traceback (most recent call last):
  File "...", line 16, in <module>
    fn()
  File "<string>", line 3, in fn
Exception:  - raise Exception()

最大的问题是,如果 eval 调用其他代码,那么 - raise Exception() 的来源就会变得困惑。

<小时/>

有没有办法让 eval 代码提供出错的行?

最佳答案

缺失的行表明 Python 无法在磁盘上找到名为 <string> 的文件。 ,这是编译后的代码片段中内置的文件名。 (尽管如果您创建一个具有完全相同名称的文件,Python 会从中打印行!)

方法 1. 您可以自己捕获异常,无论是在应用程序的顶层还是其他地方,您可以调用标准库例程 traceback.print_exc(),而不是让默认的内置回溯例程触发。它从标准库模块 linecache 中提取行。因为linecache缓存是一个简单的公共(public)Python字典,您可以用它需要打印的源代码预先填充它。请参阅:

Why does the Python linecache affect the traceback module but not regular tracebacks?

生成的代码:

import linecache
import traceback

source = 'print("Hello, world" + 1)'
source_name = 'Example'
lines = source.splitlines(True)
linecache.cache[source_name] = len(source), None, lines, source_name
compiled = compile(source, source_name, 'exec')
try:
    eval(compiled)
except Exception:
    traceback.print_exc()

方法 2. 您还可以通过自己负责打印异常来避免间接填充全局缓存:您可以让 Python 将回溯数据作为元组列表返回,单步执行他们添加缺少的行,然后最后像往常一样打印它们。

这是一个fill_in_lines()在打印完整回溯的小程序中,使用缺失的信息填充回溯的函数:

import sys
import traceback

def fill_in_lines(frames, source_name, source):
    lines = source.splitlines()
    for filename, line_number, function_name, text in frames:
        if filename == source_name:
            text = lines[line_number - 1]
        yield filename, line_number, function_name, text

source = 'print("Hello, world" + 1)'
source_name = 'Example'
compiled = compile(source, source_name, 'exec')
try:
    eval(compiled)
except Exception as e:
    _, _, tb = sys.exc_info()
    frames = traceback.extract_tb(tb)
    frames = fill_in_lines(frames, source_name, source)

    print('Traceback (most recent call last):')
    print(''.join(traceback.format_list(frames)), end='')
    print('{}: {}'.format(type(e).__name__, str(e)))

我可以在这里使用奇特的名称“Example”,因为我使用 compile() 设置它。 。在您的情况下,您可能希望传递裸字符串 '<string>'作为source_name论证。

关于python - 文件 "<string>"回溯和行预览,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47183305/

相关文章:

ios - 禁用位码时的 dSYM 下载

python - SQL ALCHEMY 关系问题 (M :1)

python - Pydev 对话框使 Eclipse Juno IDE 崩溃

python - 如何根据 ID 号列表乘以列值?

python - 在 python 3 中查找匹配项

python - 使用 arrayName 和 arrayName[ :] in Python? 有什么区别

python /Django : emulating a multidimensional layer on a MySQL database

之字形迭代器的 Pythonic 方式?

python-3.x - 在python中发送电子邮件时出错:“bytes”对象没有属性“encode”

Emacs 启动时出现 24 错误