51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

如何在Python中捕获错误的回溯信息以及源代码?

英文:

How to capture the traceback for an error in python along with source code?

问题 {#heading}

以下是翻译好的部分:

当我运行一个vscode笔记本单元格或包含以下内容的python文件时:

def foo(): return 4/0 # 这将导致除零异常

foo()

我会得到以下错误回溯,它非常有意义,并告诉我在哪一行以及哪一行的代码发生了错误:


ZeroDivisionError Traceback (most recent call last) Cell In[12], line 4 1 def foo(): 2 return 4/0 # 这将导致除零异常 ----> 4 foo()

Cell In[12], line 2, in foo() 1 def foo(): ----> 2 return 4/0

ZeroDivisionError: division by zero

但是当我使用exec块运行程序时,我无法看到源代码。我该如何捕获它?

import traceback import sys

code = """ def foo(): return 4/0 # 这将导致除零异常

foo() """

try: exec(code) except Exception as e: traceback.print_exc()

会得到以下输出:

Traceback (most recent call last): File "/var/folders/fd/f7mj1ws56pq6xvyzj4zv1r_m0000gn/T/ipykernel_39670/712868849.py", line 11, in <module> exec(code) File "<string>", line 4, in <module> File "<string>", line 2, in foo ZeroDivisionError: division by zero

英文:

When I run a vscode notebook cell or a python file with these contents:

def foo():
    return 4/0  # This will cause a division by zero exception

foo()

I get the following error traceback which is very meaningful and tells me at what line along with the line of code that errors:

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[12], line 4
      1 def foo():
      2     return 4/0  # This will cause a division by zero exception
----&gt; 4 foo()

Cell In[12], line 2, in foo() 1 def foo(): ----&amp;gt; 2 return 4/0

ZeroDivisionError: division by zero


However when I run the program using a exec block I am unable to see the source code. How do I capture this?

import traceback
import sys

code = &quot;&quot;&quot;def foo(): return 4/0 # This will cause a division by zero exception

foo() &quot;&quot;&quot;

try: exec(code) except Exception as e: traceback.print_exc()

gives:

Traceback (most recent call last):
  File &quot;/var/folders/fd/f7mj1ws56pq6xvyzj4zv1r_m0000gn/T/ipykernel_39670/712868849.py&quot;, line 11, in &lt;module&gt;
    exec(code)
  File &quot;&lt;string&gt;&quot;, line 4, in &lt;module&gt;
  File &quot;&lt;string&gt;&quot;, line 2, in foo
ZeroDivisionError: division by zero

答案1 {#1}

得分: 2

The traceback printing mechanism relies on being able to read the line from disk (using the linecache module).

For exec'd code, there is no disk (after all, that's why it's saying File "<string>", line 2).

Looking at what traceback is doing you can patch linecache.getline to do a special thing for <string>s:

import traceback
import linecache
import unittest.mock

code = """def foo(): return 4/0 # This will cause a division by zero exception

foo() """

orig_getline = linecache.getline

def new_getline(filename, lineno, *args, **kwargs): if filename == "<string>": return code.splitlines()[lineno - 1] return orig_getline(filename, lineno, *args, **kwargs)

with unittest.mock.patch("linecache.getline", new_getline): try: exec(code) except Exception as e: traceback.print_exc()

et voilà:

Traceback (most recent call last):
  File "F:\build\so-misc\so76878031.py", line 23, in <module>
    exec(code)
  File "<string>", line 4, in <module>
    foo()
  File "<string>", line 2, in foo
    return 4/0  # This will cause a division by zero exception
ZeroDivisionError: division by zero

英文:

The traceback printing mechanism relies on being able to read the line from disk (using the linecache module).

For exec'd code, there is no disk (after all, that's why it's saying File &quot;&lt;string&gt;&quot;, line 2).

Looking at what traceback is doing you can patch linecache.getline to do a special thing for &lt;string&gt;s:

import traceback
import linecache
import unittest.mock

code = &amp;quot;&amp;quot;&amp;quot;def foo(): return 4/0 # This will cause a division by zero exception

foo() &amp;quot;&amp;quot;&amp;quot;

orig_getline = linecache.getline

def new_getline(filename, lineno, *args, **kwargs): if filename == &amp;quot;&amp;lt;string&amp;gt;&amp;quot;: return code.splitlines()[lineno - 1] return orig_getline(filename, lineno, *args, **kwargs)

with unittest.mock.patch(&amp;quot;linecache.getline&amp;quot;, new_getline): try: exec(code) except Exception as e: traceback.print_exc()


et voilà:

Traceback (most recent call last):
  File &quot;F:\build\so-misc\so76878031.py&quot;, line 23, in &lt;module&gt;
    exec(code)
  File &quot;&lt;string&gt;&quot;, line 4, in &lt;module&gt;
    foo()
  File &quot;&lt;string&gt;&quot;, line 2, in foo
    return 4/0  # This will cause a division by zero exception
ZeroDivisionError: division by zero

赞(4)
未经允许不得转载:工具盒子 » 如何在Python中捕获错误的回溯信息以及源代码?