파이썬

[python] Python에서 수동으로 예외 발생(throw)

zooheon 2022. 8. 22. 23:10
반응형

except나중에 블록 을 통해 catch할 수 있도록 Python에서 예외를 발생시키는 방법은 무엇입니까?

 

Python에서 수동으로 예외를 던지거나 발생시키는 방법은 무엇입니까?

의미 론적으로 문제에 맞는 가장 구체적인 예외 생성자를 사용하십시오 .

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

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

일반 예외를 발생시키지 마십시오

제네릭을 올리지 마십시오 Exception. 그것을 잡으려면 그것을 하위 분류하는 다른 모든 더 구체적인 예외를 잡아야 합니다.

문제 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는 일반적인 예외를 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

대신 의미상 문제에 맞는 가장 구체적인 예외 생성자를 사용하세요 .

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

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

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

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

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

인쇄물

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

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

모범 사례: 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>

파이썬 3 에서 :

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

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

파이썬 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.

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

사용 예

내 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.')

 

이러지 마세요 . 맨손으로 키우는Exception것은 절대옳지 않습니다 . 대신 Aaron Hall의 훌륭한 답변 을 참조하십시오.

이보다 더 Pythonic할 수는 없습니다.

raise Exception("I know Python!")

Exception던지려는 특정 유형의 예외로 교체하십시오 .

자세한 내용 은 Python용 raise 문 설명서 를 참조하십시오.

 

Python 3에는 예외를 발생시키는 네 가지 구문이 있습니다.

  1. 예외를 일으키다
  2. 예외 발생(인수)
  3. 들어올리다
  4. original_exception에서 예외(인수) 발생

1. 예외 발생 대 2. 예외 발생(인수)

raise exception (args)예외를 발생시키는 데 사용하는 경우 args아래 예와 같이 예외 개체를 인쇄할 때 인쇄됩니다.

  # Raise exception (args)
    try:
        raise ValueError("I have raised an Exception")
    except ValueError as exp:
          print ("Error", exp)     # Output -> Error I have raised an Exception


  # Raise exception
    try:
        raise ValueError
    except ValueError as exp:
          print ("Error", exp)     # Output -> Error

3. 성명서 인상

raise인수가 없는 문은 마지막 예외를 다시 발생시킵니다 .

예외를 포착한 후 일부 작업을 수행한 다음 다시 발생시키려는 경우에 유용합니다. 그러나 이전에 예외가 없었다면 raise명령문은 TypeError예외를 발생시킵니다.

def somefunction():
    print("some cleaning")

a=10
b=0
result=None

try:
    result=a/b
    print(result)

except Exception:            # Output ->
    somefunction()           # Some cleaning
    raise                    # Traceback (most recent call last):
                             # File "python", line 8, in <module>
                             # ZeroDivisionError: division by zero

4. original_exception에서 예외(인수) 발생

이 문은 아래 예와 같이 다른 예외에 대한 응답으로 발생한 예외가 원래 예외의 세부 정보를 포함할 수 있는 예외 연결을 만드는 데 사용됩니다.

class MyCustomException(Exception):
pass

a=10
b=0
reuslt=None
try:
    try:
        result=a/b

    except ZeroDivisionError as exp:
        print("ZeroDivisionError -- ",exp)
        raise MyCustomException("Zero Division ") from exp

except MyCustomException as exp:
        print("MyException",exp)
        print(exp.__cause__)

산출:

ZeroDivisionError --  division by zero
MyException Zero Division
division by zero

 

반응형