프로그래밍 언어/Python

Python에서 수동으로 예외 발생 (throwing)

Rateye 2021. 8. 12. 13:16
728x90
반응형
질문 : Python에서 수동으로 예외 발생 (던지기)

except 블록을 통해 잡을 수 있도록 파이썬에서 예외를 어떻게 발생시킬 수 있습니까?

답변

Python에서 예외를 수동으로 생성/제기하는 방법은 무엇입니까?

 

의미 상 문제에 맞는 가장 구체적인 예외 생성자를 사용합니다 .

메시지를 구체적으로 작성하십시오. 예 :

raise ValueError('A very specific bad thing happened.')

일반 예외를 제기하지 않음

Exception 발생시키지 마십시오. 이를 포착하려면 하위 클래스를 구성하는 다른 모든 특정 예외를 포착해야합니다.0

 

문제 1: 버그 숨기기

raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.

예를 들면 :

def demo_bad_catch():
    try:
        raise ValueError('Represents a hidden bug, do not catch this')
        raise Exception('This is the exception you expect to handle')
    except Exception as error:
        print('Caught this error: ' + repr(error))

>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)

 

문제 2: 잡히지 않음

그리고 더 구체적인 catch는 일반적인 예외를 포착하지 않습니다.

def demo_no_catch():
    try:
        raise Exception('general exceptions not caught by specific handling')
    except ValueError as e:
        print('we will not catch exception: Exception')
 

>>> demo_no_catch()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling

 

모범 사례: "raise" 설명

대신, 의미 상 문제에 맞는 가장 구체적인 Exception 생성자를 사용하십시오 .

raise ValueError('A very specific bad thing happened')
                                                             

또한 임의의 수의 인수를 생성자에 전달할 수 있습니다.

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 
                                                             

이러한 인수는 Exception 개체 args 속성에 의해 액세스됩니다. 예를 들면 :

try:
    some_code_that_may_raise_our_value_error()
except ValueError as err:
    print(err.args)

출력

('message', 'foo', 'bar', 'baz')    
                                                                     

Python 2.5에서는 사용자가 Exceptions 하위 클래스를 만들고 args 사용을 중지하도록 유도하기 위해 message BaseException 에 추가되었지만 message 도입 및 args의 원래 사용 중단이 철회되었습니다 .

 

모범 사례: "except" 절

예를 들어 except 절 안에있을 때 특정 유형의 오류가 발생했음을 기록한 다음 다시 발생시킬 수 있습니다. 스택 추적을 유지하면서이를 수행하는 가장 좋은 방법은 bare raise 문을 사용하는 것입니다. 예를 들면 :

logger = logging.getLogger(__name__)
                                                                     
                                                                     try:
                                                                         do_something_in_app_that_breaks_easily()
                                                                         except AppError as error:
                                                                             logger.error(error)
                                                                                 raise                 # just this!
                                                                                     # raise AppError      # Don't do this, you'll lose the stack trace!
                                                                                     

 

반응형

 

오류를 수정하지 마십시오... 하지만 굳이 원하신다면.

sys.exc_info() )를 사용하여 스택 추적 (및 오류 값)을 보존 할 수 있지만, 이것은 오류가 발생하기 쉽고 Python 2와 3간에 호환성 문제가 raise 를 사용하여 다시 레이즈하는 것을 선호합니다.

설명하기 위해 sys.exc_info() 는 유형, 값 및 역 추적을 반환합니다.

type, value, traceback = sys.exc_info()
                                                                                     

이것은 Python 2의 구문입니다. Python 3과 호환되지 않습니다.

raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

원하는 경우 새 레이즈에서 발생하는 작업을 수정할 수 있습니다. 예를 들어 인스턴스에 대한 args

def error():
    raise ValueError('oops!')

def catch_error_modify_message():
    try:
        error()
    except ValueError:
        error_type, error_instance, traceback = sys.exc_info()
        error_instance.args = (error_instance.args[0] + ' <modification>',)
        raise error_type, error_instance, traceback

그리고 우리는 args를 수정하는 동안 전체 트레이스 백을 보존했습니다. 이것은 모범 사례 가 아니며 Python 3에서 잘못된 구문 입니다 (호환성을 유지하기가 훨씬 더 어려워 짐).

>>> catch_error_modify_message()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in catch_error_modify_message
  File "<stdin>", line 2, in error
ValueError: oops! <modification>

Python 3에서 :

raise error.with_traceback(sys.exc_info()[2])
                                                                                                                                       

다시 말하지만 수동으로 트레이스 백을 조작하지 마십시오. 효율성 이 떨어지고 오류가 발생하기 쉽습니다. 그리고 스레딩과 sys.exc_info 를 사용하는 경우 잘못된 역 추적을 얻을 수도 있습니다 (특히 제어 흐름에 예외 처리를 사용하는 경우-개인적으로 피하는 경향이 있음).

Python 3, 예외 체인

Python 3에서는 트레이스 백을 보존하는 예외를 연결할 수 있습니다.

raise RuntimeError('specific message') from error
                                                                                                                                       

주의 :

  • 이 오류 유형 제기 변경 허용하고 않는
  • 이것은 Python 2와 호환 되지 않습니다.

 

사용되지 않는 방법:

이들은 쉽게 숨기고 프로덕션 코드에 들어갈 수도 있습니다. 예외를 발생시키고 싶고, 그렇게하면 예외가 발생 하지만 의도 한 것은 아닙니다!

다음은 Python 2에서 유효하지만 Python 3에서는 유효하지 않습니다 .

raise ValueError, 'message' # Don't do this, it's deprecated!
                                                                                                                                       

훨씬 이전 버전의 Python (2.4 이하)에서만 유효하지만 여전히 문자열을 올리는 사람들을 볼 수 있습니다.

raise 'message' # really really wrong. don't do this.
                                                                                                                                       

모든 최신 버전에서는 BaseException 유형을 발생시키지 않기 때문에 TypeError 올바른 예외를 확인하지 않고 문제를 알고있는 검토자가 없으면 프로덕션에 들어갈 수 있습니다.

 

사용 예

내 API를 잘못 사용하는 경우 내 API에 대해 소비자에게 경고하기 위해 예외를 발생시킵니다.

def api_func(foo):
    '''foo should be either 'baz' or 'bar'. returns something very useful.'''
    if foo not in _ALLOWED_ARGS:
        raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))

 

제안 시 사용자 고유의 오류 유형 생성

"고의로 오류를 만들어서 예외로 들어가고 싶다"

고유 한 오류 유형을 생성 할 수 있습니다. 애플리케이션에 특정 문제가 있음을 나타내려면 예외 계층 구조에서 적절한 지점을 하위 클래스로 지정하면됩니다.

class MyAppLookupError(LookupError):
    '''raise this when there's a lookup error for my app'''

및 사용법 :

if important_key not in resource_dict and not ok_to_be_missing:
    raise MyAppLookupError('resource is missing, and that is not ok.')
출처 : https://stackoverflow.com/questions/2052390/manually-raising-throwing-an-exception-in-python
728x90
반응형