기존 정보를 보존하면서 다른 유형과 메시지로 예외를 다시 발생시킵니다.
모듈을 작성 중이며 발생할 수있는 예외 (예 : FooError
모든 foo
모듈의 특정 예외에 대한 추상 클래스 에서 상속)에 대한 통일 된 예외 계층 구조를 원합니다 . 이를 통해 모듈 사용자는 이러한 특정 예외를 포착하고 필요한 경우이를 개별적으로 처리 할 수 있습니다. 그러나 모듈에서 발생하는 많은 예외는 다른 예외로 인해 발생합니다. 예를 들어 파일의 OSError로 인해 일부 작업이 실패합니다.
필요한 것은 다른 유형과 메시지 를 갖도록 포착 된 예외 를 "랩핑"하여 예외를 포착 하는 모든 것에 의해 전파 계층 구조에 대한 정보를 더 사용할 수 있도록하는 것입니다. 그러나 기존 유형, 메시지 및 스택 추적을 잃고 싶지 않습니다. 그것은 문제를 디버깅하려는 누군가에게 유용한 정보입니다. 최상위 예외 처리기는 전파 스택을 더 높이기 전에 예외를 장식하려고하는데 최상위 처리기가 너무 늦기 때문에 좋지 않습니다.
이것은 foo
기존 유형 (예 :)에서 모듈 의 특정 예외 유형을 파생시켜 부분적으로 해결 class FooPermissionError(OSError, FooError)
되지만 기존 예외 인스턴스를 새로운 유형으로 랩핑하거나 메시지를 수정하기가 쉽지 않습니다.
Python의 PEP 3134 “Exception Chaining and Embedded Tracebacks”에서는 Python 3.0에서 예외 개체를“chaining”하기 위해 수용된 변경 사항에 대해 논의하여 기존 예외를 처리하는 동안 새로운 예외가 발생했음을 나타냅니다.
내가하려고하는 것은 관련이 있습니다. 이전 파이썬 버전에서도 작동해야하며 체인이 아닌 다형성에만 필요합니다. 이것을하는 올바른 방법은 무엇입니까?
Python 3 에서는 예외 체인을 도입 했습니다 ( PEP 3134에 설명 된대로 ). 이를 통해 예외를 제기 할 때 기존 예외를 "원인"으로 인용 할 수 있습니다.
try:
frobnicate()
except KeyError as exc:
raise ValueError("Bad grape") from exc
이로 인해 포착 된 예외는 새 예외의 일부가되고 ( "원인") 새 예외를 포착하는 모든 코드에서 사용할 수 있습니다.
이 기능을 사용하면 __cause__
속성이 설정됩니다. 내장 예외 처리기는 또한 예외의 "원인"및 "문맥" 을 트레이스 백과 함께 보고하는 방법을 알고 있습니다 .
Python 2 에서는 이 유스 케이스에 좋은 대답이없는 것으로 보입니다 ( Ian Bicking 및 Ned Batchelder에 설명되어 있음 ). 버머.
sys.exc_info ()를 사용하여 역 추적을 가져오고 PEP에서 언급 한대로 해당 역 추적과 함께 새 예외를 발생시킬 수 있습니다. 이전 유형과 메시지를 유지하려면 예외에 대해 그렇게 할 수 있지만 예외를 발견하는 것이 무엇이든 찾으면 유용합니다.
예를 들어
import sys
def failure():
try: 1/0
except ZeroDivisionError, e:
type, value, traceback = sys.exc_info()
raise ValueError, ("You did something wrong!", type, value), traceback
물론 이것은 실제로 유용하지 않습니다. 그렇다면 PEP가 필요하지 않습니다. 나는 그것을하지 않는 것이 좋습니다.
포착 한 예외 를 확장하는 고유 한 예외 유형을 작성할 수 있습니다 .
class NewException(CaughtException):
def __init__(self, caught):
self.caught = caught
try:
...
except CaughtException as e:
...
raise NewException(e)
그러나 대부분의 경우 예외를 포착하고 처리 raise
하며 원래 예외 (및 역 추적을 유지) 또는를 수행 하는 것이 더 간단하다고 생각합니다 raise NewException()
. 코드를 호출하고 있고 사용자 지정 예외 중 하나를 수신 한 경우 코드가 이미 처리해야 할 예외를 처리했을 것으로 예상됩니다. 따라서 나는 그것을 직접 접근 할 필요가 없다.
편집 : 나는 당신의 예외를 던지고 원래의 예외를 유지하는 방법에 대한이 분석 을 발견 했습니다 . 예쁜 해결책이 없습니다.
또한 여러 번 오류 발생에 대한 "래핑"이 필요하다는 것을 알았습니다.
이것은 함수 범위에 포함되어 있으며 때로는 함수 내부의 일부 줄만 래핑합니다.
Created a wrapper to be used a decorator
and context manager
:
Implementation
import inspect
from contextlib import contextmanager, ContextDecorator
import functools
class wrap_exceptions(ContextDecorator):
def __init__(self, wrapper_exc, *wrapped_exc):
self.wrapper_exc = wrapper_exc
self.wrapped_exc = wrapped_exc
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
if not exc_type:
return
try:
raise exc_val
except self.wrapped_exc:
raise self.wrapper_exc from exc_val
def __gen_wrapper(self, f, *args, **kwargs):
with self:
for res in f(*args, **kwargs):
yield res
def __call__(self, f):
@functools.wraps(f)
def wrapper(*args, **kw):
with self:
if inspect.isgeneratorfunction(f):
return self.__gen_wrapper(f, *args, **kw)
else:
return f(*args, **kw)
return wrapper
Usage examples
decorator
@wrap_exceptions(MyError, IndexError)
def do():
pass
when calling do
method, don't worry about IndexError
, just MyError
try:
do()
except MyError as my_err:
pass # handle error
context manager
def do2():
print('do2')
with wrap_exceptions(MyError, IndexError):
do()
inside do2
, in the context manager
, if IndexError
is raised, it will be wrapped and raised MyError
The most straighforward solution to your needs should be this:
try:
upload(file_id)
except Exception as upload_error:
error_msg = "Your upload failed! File: " + file_id
raise RuntimeError(error_msg, upload_error)
In this way you can later print your message and the specific error throwed by the upload function
'Programing' 카테고리의 다른 글
출시 전 Android 애플리케이션 최적화 (0) | 2020.07.14 |
---|---|
C ++에서 숫자를 문자열로 변환하거나 그 반대로 변환하는 방법 (0) | 2020.07.14 |
C ++에서 포인터에 대한 참조 전달 (0) | 2020.07.14 |
Phonegap Cordova 설치 창 (0) | 2020.07.14 |
구조체가 상속을 지원하지 않는 이유는 무엇입니까? (0) | 2020.07.14 |