programing

예외 개체에서 추적 정보 추출

nasanasas 2020. 8. 30. 08:43
반응형

예외 개체에서 추적 정보 추출


출처를 알 수없는 예외 객체가 주어지면 추적을 얻을 수있는 방법이 있습니까? 다음과 같은 코드가 있습니다.

def stuff():
   try:
       .....
       return useful
   except Exception as e:
       return e

result = stuff()
if isinstance(result, Exception):
    result.traceback <-- How?

Exception 객체가있는 경우 어떻게 트레이스 백을 추출 할 수 있습니까?


이 질문에 대한 답은 사용중인 Python 버전에 따라 다릅니다.

Python 3에서

간단합니다. 예외 __traceback__에는 트레이스 백을 포함 하는 속성이 제공됩니다. 이 속성은 쓰기 가능하며 with_traceback예외 방법을 사용하여 편리하게 설정할 수 있습니다 .

raise Exception("foo occurred").with_traceback(tracebackobj)

이러한 기능은 raise문서의 일부로 최소한으로 설명됩니다 .

답변의이 부분에 대한 모든 크레딧 은이 정보처음 게시 한 Vyctor에게 가야합니다 . 이 답변이 맨 위에 붙어 있고 Python 3가 점점 보편화되고 있기 때문에 여기에 포함되었습니다.

Python 2에서

성가 시게 복잡합니다. 역 추적의 문제점은 스택 프레임에 대한 참조를 가지고 있고, 스택 프레임은 프레임 스택에 대한 참조를 가지고 역 추적에 대한 참조해야한다는 것입니다 에 ... 참조가 당신이 아이디어를 얻을 수 있습니다. 이로 인해 가비지 수집기에 문제가 발생합니다. ( 처음 지적한 ecatmur 에게 감사드립니다 .)

이 문제를 해결하는 좋은 방법은 을 떠난 후 외과 적 으로주기를 중단except 하는 것입니다. 이것이 Python 3이하는 일입니다. Python 2 솔루션은 훨씬 더 추악합니다. 내에서만 작동sys.exc_info() 하는 임시 함수를 제공 합니다 . 예외, 예외 유형 및 현재 처리중인 예외에 대한 추적을 포함하는 튜플을 반환합니다.except

따라서 except내부에 있다면 모듈 sys.exc_info()과 함께의 출력을 사용하여 traceback다양한 유용한 작업을 수행 할 수 있습니다.

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

당신의 편집 표시하지만, 당신은 추적 얻을하려는 이 후, 당신의 예외가 처리되지 않은 경우 인쇄 한을 이미 처리되었습니다. 그것은 훨씬 더 어려운 질문입니다. 불행히도 예외가 처리되지 않으면 sys.exc_info반환 (None, None, None)됩니다. 다른 관련 sys속성도 도움이되지 않습니다. sys.exc_traceback예외가 처리되지 않으면 더 이상 사용되지 않으며 정의되지 않습니다. sys.last_traceback완벽 해 보이지만 대화 형 세션에서만 정의 된 것처럼 보입니다.

예외 발생 방법을 제어 할 수있는 경우 inspect사용자 지정 예외 를 사용하여 일부 정보를 저장할 수 있습니다. 그러나 나는 그것이 어떻게 작동하는지 완전히 확신하지 못합니다.

진실을 말하면 예외를 포착하고 반환하는 것은 특이한 일입니다. 어쨌든 리팩토링해야한다는 신호일 수 있습니다.


이후 파이썬 3.0 [3109 PEP] (가) 클래스에 내장은 Exception__traceback__포함 속성 traceback object(파이썬 3.2.3로)를 :

>>> try:
...     raise Exception()
... except Exception as e:
...     tb = e.__traceback__
...
>>> tb
<traceback object at 0x00000000022A9208>

문제는 인터넷 검색__traceback__잠시 동안 몇 개의 기사 만 찾았지만 .NET을 사용해야하는 이유 또는 이유를 설명하는 기사가 없다는 것 __traceback__입니다.

그러나에 대한 Python 3 문서는 다음과raise 같이 말합니다.

A traceback object is normally created automatically when an exception is raised and attached to it as the __traceback__ attribute, which is writable.

So I assume it's meant to be used.


A way to get traceback as a string from an exception object in Python 3:

import traceback

# `e` is an exception object that you get from somewhere
traceback_str = ''.join(traceback.format_tb(e.__traceback__))

traceback.format_tb(...) returns a list of strings. ''.join(...) joins them together. For more reference, please visit: https://docs.python.org/3/library/traceback.html#traceback.format_tb


As an aside, if you want to actually get the full traceback as you would see it printed to your terminal, you want this:

>>> try:
...     print(1/0)
... except Exception as e:
...     exc = e
...
>>> exc
ZeroDivisionError('division by zero')
>>> tb_str = traceback.format_exception(etype=type(exc), value=exc, tb=exc.__traceback__)
>>> tb_str
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: division by zero\n']
>>> print("".join(tb_str))
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

If you use format_tb as above answers suggest you'll get less information:

>>> tb_str = "".join(traceback.format_tb(exc.__traceback__))
>>> print("".join(tb_str))
  File "<stdin>", line 2, in <module>

There's a very good reason the traceback is not stored in the exception; because the traceback holds references to its stack's locals, this would result in a circular reference and (temporary) memory leak until the circular GC kicks in. (This is why you should never store the traceback in a local variable.)

About the only thing I can think of would be for you to monkeypatch stuff's globals so that when it thinks it's catching Exception it's actually catching a specialised type and the exception propagates to you as the caller:

module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
    stuff()
except Exception:
    import sys
    print sys.exc_info()

참고URL : https://stackoverflow.com/questions/11414894/extract-traceback-info-from-an-exception-object

반응형