Python 获取导致异常的异常描述和堆栈跟踪,全部为字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4564559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 16:20:56  来源:igfitidea点击:

Get exception description and stack trace which caused an exception, all as a string

pythonpython-2.7exception-handlingstack-trace

提问by bluish

I've seen a lot of posts about stack trace and exceptions in Python. But haven't found what I need.

我看过很多关于 Python 中堆栈跟踪和异常的帖子。但是还没有找到我需要的。

I have a chunk of Python 2.7 code that may raise an exception. I would like to catch it and assign to a stringits full description and the stack trace that caused the error (simply all we use to see on the console). I need this string to print it to a text box in the GUI.

我有一大段 Python 2.7 代码可​​能会引发异常。我想捕获它并将其完整描述和导致错误的堆栈跟踪分配给一个字符串(只是我们在控制台上看到的所有内容)。我需要此字符串将其打印到 GUI 中的文本框。

Something like this:

像这样的东西:

try:
    method_that_can_raise_an_exception(params)
except Exception as e:
    print_to_textbox(complete_exception_description(e))

The problem is: what is the function complete_exception_description?

问题是:函数什么complete_exception_description

采纳答案by kindall

See the tracebackmodule, specifically the format_exc()function. Here.

请参阅traceback模块,特别是format_exc()功能。在这里

import traceback

try:
    raise ValueError
except ValueError:
    tb = traceback.format_exc()
else:
    tb = "No error"
finally:
    print tb

回答by aeter

>>> import sys
>>> import traceback
>>> try:
...   5 / 0
... except ZeroDivisionError as e:
...   type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
['  File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

You use sys.exc_info()to collect the information and the functions in the tracebackmodule to format it. Hereare some examples for formatting it.

您使用sys.exc_info()收集traceback模块中的信息和函数以对其进行格式化。 以下是格式化它的一些示例。

The whole exception string is at:

整个异常字符串位于:

>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']

回答by Aaron Hall

Let's create a decently complicated stacktrace, in order to demonstrate that we get the full stacktrace:

让我们创建一个相当复杂的堆栈跟踪,以证明我们获得了完整的堆栈跟踪:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Logging the full stacktrace

记录完整的堆栈跟踪

A best practice is to have a logger set up for your module. It will know the name of the module and be able to change levels (among other attributes, such as handlers)

最佳实践是为您的模块设置一个记录器。它将知道模块的名称并能够更改级别(以及其他属性,例如处理程序)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

And we can use this logger to get the error:

我们可以使用这个记录器来获取错误:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

Which logs:

哪些日志:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

And so we get the same output as when we have an error:

因此,我们得到与出现错误时相同的输出:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Getting just the string

只获取字符串

If you really just want the string, use the traceback.format_excfunction instead, demonstrating logging the string here:

如果您真的只想要字符串,请改用该traceback.format_exc函数,在此处演示记录字符串:

import traceback
try:
    do_something_that_might_error()
except Exception as error:
    just_the_string = traceback.format_exc()
    logger.debug(just_the_string)

Which logs:

哪些日志:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

回答by samaspin

You might also consider using the built-in Python module, cgitb, to get some really good, nicely formatted exception information including local variable values, source code context, function parameters etc..

您还可以考虑使用内置的 Python 模块cgitb来获取一些非常好的、格式良好的异常信息,包括局部变量值、源代码上下文、函数参数等。

For instance for this code...

例如对于这段代码......

import cgitb
cgitb.enable(format='text')

def func2(a, divisor):
    return a / divisor

def func1(a, b):
    c = b - 5
    return func2(a, c)

func1(1, 5)

we get this exception output...

我们得到这个异常输出...

ZeroDivisionError
Python 3.4.2: C:\tools\python\python.exe
Tue Sep 22 15:29:33 2015

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 c:\TEMP\cgittest2.py in <module>()
    7 def func1(a, b):
    8   c = b - 5
    9   return func2(a, c)
   10
   11 func1(1, 5)
func1 = <function func1>

 c:\TEMP\cgittest2.py in func1(a=1, b=5)
    7 def func1(a, b):
    8   c = b - 5
    9   return func2(a, c)
   10
   11 func1(1, 5)
global func2 = <function func2>
a = 1
c = 0

 c:\TEMP\cgittest2.py in func2(a=1, divisor=0)
    3
    4 def func2(a, divisor):
    5   return a / divisor
    6
    7 def func1(a, b):
a = 1
divisor = 0
ZeroDivisionError: division by zero
    __cause__ = None
    __class__ = <class 'ZeroDivisionError'>
    __context__ = None
    __delattr__ = <method-wrapper '__delattr__' of ZeroDivisionError object>
    __dict__ = {}
    __dir__ = <built-in method __dir__ of ZeroDivisionError object>
    __doc__ = 'Second argument to a division or modulo operation was zero.'
    __eq__ = <method-wrapper '__eq__' of ZeroDivisionError object>
    __format__ = <built-in method __format__ of ZeroDivisionError object>
    __ge__ = <method-wrapper '__ge__' of ZeroDivisionError object>
    __getattribute__ = <method-wrapper '__getattribute__' of ZeroDivisionError object>
    __gt__ = <method-wrapper '__gt__' of ZeroDivisionError object>
    __hash__ = <method-wrapper '__hash__' of ZeroDivisionError object>
    __init__ = <method-wrapper '__init__' of ZeroDivisionError object>
    __le__ = <method-wrapper '__le__' of ZeroDivisionError object>
    __lt__ = <method-wrapper '__lt__' of ZeroDivisionError object>
    __ne__ = <method-wrapper '__ne__' of ZeroDivisionError object>
    __new__ = <built-in method __new__ of type object>
    __reduce__ = <built-in method __reduce__ of ZeroDivisionError object>
    __reduce_ex__ = <built-in method __reduce_ex__ of ZeroDivisionError object>
    __repr__ = <method-wrapper '__repr__' of ZeroDivisionError object>
    __setattr__ = <method-wrapper '__setattr__' of ZeroDivisionError object>
    __setstate__ = <built-in method __setstate__ of ZeroDivisionError object>
    __sizeof__ = <built-in method __sizeof__ of ZeroDivisionError object>
    __str__ = <method-wrapper '__str__' of ZeroDivisionError object>
    __subclasshook__ = <built-in method __subclasshook__ of type object>
    __suppress_context__ = False
    __traceback__ = <traceback object>
    args = ('division by zero',)
    with_traceback = <built-in method with_traceback of ZeroDivisionError object>

The above is a description of an error in a Python program.  Here is
the original traceback:

Traceback (most recent call last):
  File "cgittest2.py", line 11, in <module>
    func1(1, 5)
  File "cgittest2.py", line 9, in func1
    return func2(a, c)
  File "cgittest2.py", line 5, in func2
    return a / divisor
ZeroDivisionError: division by zero

回答by user 1155692

my 2-cents:

我的 2 美分:

import sys, traceback
try: 
  ...
except Exception, e:
  T, V, TB = sys.exc_info()
  print ''.join(traceback.format_exception(T,V,TB))

回答by Erwin Mayer

With Python 3, the following code will format an Exceptionobject exactly as would be obtained using traceback.format_exc():

使用 Python 3,以下代码将Exception完全按照使用 获得的格式设置对象traceback.format_exc()

import traceback

try: 
    method_that_can_raise_an_exception(params)
except Exception as ex:
    print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))

The advantage being that only the Exceptionobject is needed (thanks to the recorded __traceback__attribute), and can therefore be more easily passed as an argument to another function for further processing.

优点是只Exception需要对象(由于记录的__traceback__属性),因此可以更容易地作为参数传递给另一个函数以进行进一步处理。

回答by Mike N

For those using Python-3

对于那些使用Python-3 的人

Using tracebackmodule and exception.__traceback__one can extract the stack-trace as follows:

使用tracebackmodule 和exception.__traceback__one 可以提取堆栈跟踪,如下所示:

  • grab the currentstack-trace using traceback.extract_stack()
  • remove the last three elements (as those are entries in the stack that got me to my debug function)
  • append the __traceback__from the exception object using traceback.extract_tb()
  • format the whole thing using traceback.format_list()
  • 使用获取当前堆栈跟踪traceback.extract_stack()
  • 删除最后三个元素(因为它们是让我进入调试功能的堆栈中的条目)
  • 使用__traceback__从异常对象附加traceback.extract_tb()
  • 使用格式化整个事情 traceback.format_list()
import traceback
def exception_to_string(excp):
   stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__)  # add limit=?? 
   pretty = traceback.format_list(stack)
   return ''.join(pretty) + '\n  {} {}'.format(excp.__class__,excp)

A simple demonstration:

一个简单的演示:

def foo():
    try:
        something_invalid()
    except Exception as e:
        print(exception_to_string(e))

def bar():
    return foo()

We get the following output when we call bar():

当我们调用时,我们得到以下输出bar()

  File "./test.py", line 57, in <module>
    bar()
  File "./test.py", line 55, in bar
    return foo()
  File "./test.py", line 50, in foo
    something_invalid()

  <class 'NameError'> name 'something_invalid' is not defined

回答by qbolec

I defined following helper class:

我定义了以下帮助类:

import traceback
class TracedExeptions(object):
    def __init__(self):
        pass
    def __enter__(self):
        pass

    def __exit__(self, etype, value, tb):
      if value :
        if not hasattr(value, 'traceString'):
          value.traceString = "\n".join(traceback.format_exception(etype, value, tb))
        return False
      return True

Which I can later use like this:

我以后可以这样使用:

with TracedExeptions():
  #some-code-which-might-throw-any-exception

And later can consume it like this:

稍后可以像这样使用它:

def log_err(ex):
  if hasattr(ex, 'traceString'):
    print("ERROR:{}".format(ex.traceString));
  else:
    print("ERROR:{}".format(ex));

(Background: I was frustraded because of using Promises together with Exceptions, which unfortunately passes exceptions raised in one place to a on_rejected handler in another place, and thus it is difficult to get the traceback from original location)

(背景:我很沮丧,因为将Promises 与 s 一起使用Exception,不幸的是将一个地方引发的异常传递给另一个地方的 on_rejected 处理程序,因此很难从原始位置获取回溯)

回答by SamuelN

If you would like to get the same information given when an exception isn't handled you can do something like this. Do import tracebackand then:

如果您想在未处理异常时获得相同的信息,您可以执行以下操作。做import traceback然后:

try:
    ...
except Exception as e:
    print(traceback.print_tb(e.__traceback__))

I'm using Python 3.7.

我正在使用 Python 3.7。

回答by don_vanchos

For Python 3.5+:

对于Python 3.5+

So, you can get the stacktrace from your exception as from any other exception. Use traceback.TracebackExceptionfor it (just replace exwith your exception):

因此,您可以像从任何其他异常一样从异常中获取堆栈跟踪。使用traceback.TracebackException它(只需更换ex您的除外):

print("".join(traceback.TracebackException.from_exception(ex).format())

An extended example and other features to do this:

执行此操作的扩展示例和其他功能:

import traceback

try:
    1/0
except Exception as ex:
    print("".join(traceback.TracebackException.from_exception(ex).format()) == traceback.format_exc() == "".join(traceback.format_exception(type(ex), ex, ex.__traceback__))) # This is True !!
    print("".join(traceback.TracebackException.from_exception(ex).format()))

The output will be something like this:

输出将是这样的:

True
Traceback (most recent call last):
  File "untidsfsdfsdftled.py", line 29, in <module>
    1/0
ZeroDivisionError: division by zero