2013-05-07 4 views
57

파이썬에서 예외 체인을 사용하는 표준 방법이 있습니까? 자바 예외 '에 의해 발생'처럼?파이썬 예외 체인

다음은 배경입니다.

나는 하나 개의 주 예외 클래스 DSError와 모듈이 :

class DSError(Exception): 
    pass 

이 어딘가에이 모듈 내에있을 것입니다 :

try: 
    v = my_dict[k] 
    something(v) 
except KeyError as e: 
    raise DSError("no key %s found for %s" % (k, self)) 
except ValueError as e: 
    raise DSError("Bad Value %s found for %s" % (v, self)) 
except DSError as e: 
    raise DSError("%s raised in %s" % (e, self)) 

는 기본적으로이 조각은 DSError을 던져 무슨 일이 있었는지 말해해야하며, 왜.

try: 
    v = my_dict[k] 
    something(v) 
except Exception as e: 
    raise DSError(self, v, e) # Exception chained... 

이 표준 파이썬 방법입니다 것은 try 블록이 다른 예외를 많이 던질 수있는, 그래서 뭔가를 할 수 있다면 내가 선호하는 것이다? 다른 모듈에서 예외 체인을 보지 못했지만 파이썬에서 어떻게 처리 되었습니까?

+2

: 파이썬 2에서 수행 할 수있는

Traceback (most recent call last): File "t.py", line 2, in <module> v = {}['a'] KeyError: 'a' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "t.py", line 4, in <module> raise ValueError('failed') ValueError: failed 

같이, 사용자가 예외 클래스에 속성을 추가 할 수 있습니다 : 기본 쇼 같은 예외 처리 중에 발생한 모든 예외에 의해 파이썬 3 것 와우, 고마워요. @ jamylak! 당신도 내 눈을 고정하기 전에 :-) – Ayman

+0

예, 그래서 그 작은 변화 * *를 만들지 않았기 때문에 여분의 단어를 추가해야했습니다 : ( – jamylak

+0

출력을 어떻게 하시겠습니까? 원래 예외의 스택 추적을 실제로 원한다면 또는 원래 예외를 요약하는 단일 메시지로 자신의 예외를 그냥두고 싶다면? – BrenBarn

답변

81

Exception chaining 당신이 쓸 수 파이썬 3에서만 사용할 수 있습니다 :

Traceback (most recent call last): 
    File "t.py", line 2, in <module> 
    v = {}['a'] 
KeyError: 'a' 

The above exception was the direct cause of the following exception: 

Traceback (most recent call last): 
    File "t.py", line 4, in <module> 
    raise ValueError('failed') from e 
ValueError: failed 
같은 출력을 얻을 수

try: 
    v = {}['a'] 
except KeyError as e: 
    raise ValueError('failed') from e 

대부분의 경우 from이 필요하지 않습니다.

class MyError(Exception): 
    def __init__(self, message, cause): 
     super(MyError, self).__init__(message + u', caused by ' + repr(cause)) 
     self.cause = cause 

try: 
    v = {}['a'] 
except KeyError as e: 
    raise MyError('failed', e) 
+2

파이썬 2의 경우 추적 요청을 저장하고 싶다면 - 어느 것이 _must_ want - [+ repr (cause), None, sys.exc_info (2)에 의해 발생하는 MyError (message + u) http://stackoverflow.com/a/1350981/281545) –

+1

"대부분의 경우에"필요하거나 유용한 예제가 있습니까? – timgeb

+2

@timgeb [PEP 3134] (https://www.python.org/dev/peps/pep-3134/)에는 체인을위한 두 가지 상황이 있습니다. 하나는 오류 처리 코드로 인해 다른 예외가 발생하고 다른 하나는 예외입니다. 예외는 의도적으로 다른 예외로 변환되었습니다. 'from e'는 의도적 인 경우이며, 위의 답과 같이 출력의 메시지를 변경합니다. –

4

이게 당신이 원하는 것입니까?

class MyError(Exception): 
    def __init__(self, other): 
     super(MyError, self).__init__(other.message) 

>>> try: 
...  1/0 
... except Exception, e: 
...  raise MyError(e) 
Traceback (most recent call last): 
    File "<pyshell#27>", line 4, in <module> 
    raise MyError(e) 
MyError: division by zero 

원래 예외 객체를 저장하려면

, 당신은 확실히 자신의 예외 클래스의 __init__에서 수행 할 수 있습니다. 원본에 대한 정보를 얻을 수 있도록 예외의 traceback 속성에 액세스 할 수 있습니다 이후

class MyError(Exception): 
    def __init__(self, other): 
     self.traceback = sys.exc_info() 
     super(MyError, self).__init__(other.message) 

: 당신은 실제로 예외 객체 자체가 예외가 발생한 위치에 대한 많은 유용한 정보를 제공하지 않기 때문에 역 추적을 저장 할 수 있습니다 예외. (파이썬 3는 이미 예외 객체의 __traceback__ 속성으로이를 제공합니다.)

+0

거의 예외는 아니지만 실제 예외 객체가 아닌 체인 된 예외 메시지 만 사용하기 때문에 이것이 '부정 행위'라고 생각했습니다. 즉, 제로에 의한 실제 나누기가 어디에서 발생했는지는 알 수 없지만, 그저 잡히지 않았을뿐입니다. – Ayman

+0

@Ayman : 편집 된 답변보기.당신이해야 할 일은 추적 기록을 잡고 저장하는 것입니다. 그러나 원래 예외의 모든 정보를 실제 예외처럼 추적에 표시하려면 Phihag가 파이썬 2에서 수행 할 수 없다는 것이 옳습니다. 예전의 추적 추적을 수동으로 인쇄해야합니다 예외 메시지의 일부로 – BrenBarn

+0

감사. 나는 sys.exc_info()에 대해 몰랐다. 나는 이것을 역시 대답으로 받아 들일 것이다 :-) – Ayman