출처를 알 수없는 예외 객체가 주어지면 추적을 얻을 수있는 방법이 있습니까? 다음과 같은 코드가 있습니다.
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
같이 말합니다.
트레이스 백 객체는 일반적으로 예외가 발생하고
__traceback__
쓰기 가능한 속성 으로 첨부 될 때 자동으로 생성됩니다 .
그래서 나는 그것이 사용되어야한다고 생각합니다.
답변
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(...)
문자열 목록을 반환합니다. ''.join(...)
함께 결합합니다. 자세한 내용은 https://docs.python.org/3/library/traceback.html#traceback.format_tb 를 방문 하세요.
답변
제쳐두고, 터미널에 인쇄 된 것처럼 전체 트레이스 백을 실제로 얻으려면 다음을 원합니다.
>>> 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
format_tb
위의 답변으로 사용 하면 더 적은 정보를 얻을 수 있습니다.
>>> tb_str = "".join(traceback.format_tb(exc.__traceback__))
>>> print("".join(tb_str))
File "<stdin>", line 2, in <module>
답변
트레이스 백이 예외에 저장되지 않는 아주 좋은 이유가 있습니다. 트레이스 백은 스택의 로컬에 대한 참조를 보유하기 때문에 순환 GC가 시작될 때까지 순환 참조 및 (임시) 메모리 누수가 발생합니다. (이것이 트레이스 백을 로컬 변수에 저장 해서는 안되는 이유 입니다.)
내가 생각할 수있는 유일한 것은 당신이 monkeypatch stuff
의 전역을 잡는 것이라고 생각할 때 Exception
실제로 특수 유형을 잡는 것이고 예외는 호출자로서 당신에게 전파되는 것입니다.
module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
stuff()
except Exception:
import sys
print sys.exc_info()
답변
