programing

즉시 다시 발생하지 않으면 예외 추적이 숨겨집니다.

nasanasas 2020. 11. 16. 21:36
반응형

즉시 다시 발생하지 않으면 예외 추적이 숨겨집니다.


다음과 유사한 코드가 있습니다.

import sys

def func1():
    func2()

def func2():
    raise Exception('test error')

def main():
    err = None

    try:
        func1()
    except:
        err = sys.exc_info()[1]
        pass

    # some extra processing, involving checking err details (if err is not None)

    # need to re-raise err so caller can do its own handling
    if err:
        raise err

if __name__ == '__main__':
    main()

func2나는 다음 역 추적을받을 예외가 발생 :

Traceback (most recent call last):
  File "err_test.py", line 25, in <module>
    main()
  File "err_test.py", line 22, in main
    raise err
Exception: test error

여기에서 예외가 어디에서 오는지 알 수 없습니다. 원래 트레이스 백이 손실됩니다.

원래 트레이스 백을 보존하고 다시 올릴 수있는 방법은 무엇입니까? 다음과 비슷한 것을보고 싶습니다.

Traceback (most recent call last):
  File "err_test.py", line 26, in <module>
    main()
  File "err_test.py", line 13, in main
    func1()
  File "err_test.py", line 4, in func1
    func2()
  File "err_test.py", line 7, in func2
    raise Exception('test error')
Exception: test error

공백 raise은 마지막 예외를 발생시킵니다.

# need to re-raise err so caller can do its own handling
if err:
    raise

raise somethingPython 을 사용 something하는 경우 방금 전에 포착 된 예외 인지 또는 새 스택 추적이있는 새로운 예외 인지 알 수있는 방법이 없습니다 . 이것이 raise스택 추적을 유지하는 공백이있는 이유 입니다.

여기에서 참조


예외 수정하고 다시 던질 수 있습니다.

표현식이 없으면 raise현재 범위에서 활성화 된 마지막 예외를 다시 발생시킵니다. 현재 범위에서 예외가 활성화되지 않은 경우 TypeError오류임을 나타내는 예외가 발생합니다 (IDLE에서 실행중인 경우 Queue.Empty예외가 대신 발생 함).

그렇지 않으면 생략 된 표현식의 값으로 raise사용하여 세 개의 객체를 얻기 위해 표현식을 평가합니다 None. 처음 두 개체는 예외의 유형과 값을 결정하는 데 사용됩니다.

세 번째 개체가 존재하고는 없으면 None역 추적 개체 여야하며 (표준 유형 계층 구조 섹션 참조) 예외가 발생한 위치로 현재 위치 대신 대체됩니다. 세 번째 개체가 있고 역 추적 개체 또는가 아닌 None경우 TypeError예외가 발생합니다.

의 three-expression 형식은 raise에서 예외를 투명하게 다시 발생시키는 데 유용 except하지만 raise다시 발생시킬 예외가 현재 범위에서 가장 최근에 활성화 된 예외 인 경우에는 표현식이없는 것이 좋습니다.

따라서 예외를 수정하고 다시 발생 시키려면 다음과 같이 할 수 있습니다.

try:
    buggy_code_which_throws_exception()
except Exception as e:
    raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]

traceback 모듈 sys.exc_info()과 함께 예외에 대한 많은 정보를 얻을 수 있습니다.

코드에 다음 확장을 시도하십시오.

import sys
import traceback

def func1():
    func2()

def func2():
    raise Exception('test error')

def main():

    try:
        func1()
    except:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        # Do your verification using exc_value and exc_traceback

        print "*** print_exception:"
        traceback.print_exception(exc_type, exc_value, exc_traceback,
                                  limit=3, file=sys.stdout)

if __name__ == '__main__':
    main()

이것은 당신이 원하는 것과 비슷하게 인쇄 될 것입니다.

*** print_exception:
Traceback (most recent call last):
  File "err_test.py", line 14, in main
    func1()
  File "err_test.py", line 5, in func1
    func2()
  File "err_test.py", line 8, in func2
    raise Exception('test error')
Exception: test error

While @Jochen's answer works well in the simple case, it is not capable of handling more complex cases, where you are not directly catching and rethrowing, but are for some reason given the exception as an object and wish to re-throw in a completely new context (i.e. if you need to handle it in a different process).

In this case, I propose the following:

  1. get the original exc_info
  2. format the original error message, with stack trace
  3. throw a new exception with that full error message (stack trace incl.) embedded

Before you do this, define a new exception type that you will rethrow later...

class ChildTaskException(Exception):
    pass

In the offending code...

import sys
import traceback

try:
    # do something dangerous
except:
    error_type, error, tb = sys.exc_info()
    error_lines = traceback.format_exception(error_type, error, tb)
    error_msg = ''.join(error_lines)
    # for example, if you are doing multiprocessing, you might want to send this to another process via a pipe
    connection.send(error_msg)

Rethrow...

# again, a multiprocessing example of receiving that message through a pipe
error_msg = pcon.recv()
raise ChildTaskException(error_msg)

Your main function needs to look like this:

def main():
    try:
        func1()
    except Exception, err:
        # error processing
        raise

This is the standard way of handling (and re-raising) errors. Here is a codepad demonstration.

참고URL : https://stackoverflow.com/questions/4825234/exception-traceback-is-hidden-if-not-re-raised-immediately

반응형