파이썬에서 예외를 수동으로 발생 (throw)


2263

파이썬에서 예외를 발생시켜 나중에 except블록을 통해 예외를 잡을 수 있습니까?

답변:


2936

파이썬에서 수동으로 예외를 발생 / 발생시키는 방법은 무엇입니까?

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

메시지에 구체적으로 설명하십시오. 예 :

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 : 잡을 수 없습니다

그리고 더 구체적인 캐치는 일반적인 예외를 포착하지 못합니다.

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

이러한 인수는 객체 의 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에서는 실제 message속성이 추가되어 BaseException사용자가 예외를 서브 클래스 화하고 사용을 중지하도록 권장 args했지만 arg 의 도입 message및 원래 사용 중단이 취소되었습니다 .

모범 사례 : 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()있지만, 이 방법이 더 오류가 발생하기 쉬운입니다 및 파이썬 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

그리고 우리는 인수를 수정하면서 전체 역 추적을 유지했습니다. 이것은 모범 사례 가 아니며 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.')

19
이것에 감사드립니다. 정확히 내가 필요한 것입니다. 맨손으로 raise스택 추적을 중단하지 않고 여러 수준의 코드 실행에서 사용자 정의 오류 디버깅을 수행 할 수있었습니다.
— CaffeineConnoisseur

이것은 좋은 대답입니다. 그러나 여전히 많은 2.7 코드로 작업하고 있으며 종종 입력 파일 위치 또는 일부 변수 값과 같은 예기치 않은 예외에 정보를 추가하려고하지만 원래 스택과 예외는 유지하려고합니다. 로그 할 수는 있지만 때로는 부모 코드가 궁극적으로 처리하는 경우 로그를 원하지 않습니다. raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]내가 원하는 것을하는 것처럼 보이며 결코 문제가 발생하지 않았습니다. 그러나 받아 들여지는 연습이 아니라 해키 느낌이 듭니다. 더 좋은 방법이 있습니까?
— Michael Scheper

2
@brennanyoung 그런 맥락에서 SyntaxError를 발생시키는 것이 혼란 스러울 수 있다고 생각합니다. 아마도 사용자 정의 예외를 발생시켜야합니다. 여기에 방법을 설명합니다 : stackoverflow.com/a/26938914/541136
— Aaron Hall

2
전체 인용문은 "시스템에 존재하지 않는 모든 내장 예외는이 클래스에서 파생됩니다. 모든 사용자 정의 예외도이 클래스에서 파생되어야합니다." 이는 대부분 Exception부모 클래스 에서 파생되지 않은 4 가지 예외 중 하나를 사용하지 말아야한다는 것을 의미합니다. 보다 구체적인 것을 서브 클래 싱 할 수 있으며, 의미가있는 경우 그렇게해야합니다.
— Aaron Hall

1
" 모범 사례 : except 절 " 의 예에서는 정의되지 않은 AppError예외 를 사용합니다 . 다음과 같은 내장 오류를 사용하는 것이 좋습니다.AttributeError
— Stevoisiak

530

이 작업을 수행하지 마십시오 . 베어를 올리는 Exception것이 절대적으로 옳은 일이 아닙니다 . 대신 Aaron Hall의 훌륭한 답변을 참조하십시오 .

이보다 더 많은 파이썬을 얻을 수는 없습니다.

raise Exception("I know python!")

더 많은 정보를 원하시면 파이썬에 대한 raise 문 문서 를 참조하십시오 .


67
아니요 괜찮아요! 이것은 당신이 잡는 것에 대해 구체적 일 가능성을 제거합니다. 그것을하는 것은 완전히 잘못된 방법입니다. 이 대신 Aaron Hall의 훌륭한 답변을 살펴보십시오. 이 시간은 내가 대답 당 하나 이상의 downvote를 줄 수 있기를 바랍니다.
— Dawood ibn Kareem

27
@PeterR 다운 보트가 거의 없다는 것도 끔찍합니다. 이 답변을 읽는 사람이라면 누구도이 일을하지 마십시오! 정답은 Aaron Hall의 것입니다.
— 다우드 이븐 카림

6
왜 이것이 잘못되었거나 그렇게 나쁜지에 대해 더 자세한 설명이 있어야한다고 생각합니다.
— Charlie Parker

9
@CharlieParker 있습니다. Aaron Hall의 답변 의 첫 번째 부분입니다 .
— Dinei

5
이 답변에 삭제 플래그를 지정할 수없는 이유는 무엇입니까? 이미 93 개의 downvotes를 얻었습니다!
— codeforester

54

Python3에는 예외 예외에 대한 4 가지 구문이 있습니다.

1. raise exception 
2. raise exception (args) 
3. raise
4. raise exception (args) from original_exception

1. 예외 제기 vs. 예외 제기 (args)

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 execption 
    try:
        raise ValueError
    except ValueError as exp:
        print ("Error", exp)     # Output -> Error 

3. 인상

raise인수가없는 진술은 마지막 예외를 다시 발생시킵니다. 이는 예외를 포착 한 후 일부 조치를 수행 한 후 다시 발생시키려는 경우에 유용합니다. 그러나 이전에 예외가 없었 으면 raisestatement는 TypeErrorException을 발생시킵니다.

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에서 예외 (args)를 발생시킵니다.

이 명령문은 다른 예외에 대한 응답으로 발생한 예외에 아래 예에 표시된대로 원래 예외의 세부 사항을 포함 할 수있는 예외 체인을 작성하는 데 사용됩니다.

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

7
참고 PEP8는 선호하시기 바랍니다 exception(args)이상exception (args)
— Gloweye

또한 raise exception(args) from None현재 활성화 된 예외가 처리되어 더 이상 관심 대상이 아니라고 말할 수 있습니다. 그렇지 않으면 except블록 내에서 예외가 발생하고 처리되지 않으면 두 예외에 대한 추적이 "위의 예외를 처리하는 동안 다른 예외가 발생했습니다"라는 메시지로 구분되어 표시됩니다.
— cg909

35

예상치 못한 조건에 대한 응답으로 예외를 throw해야하는 예외적 인 상황에서 포착하려는 의도는 없지만, 발생하는 경우 디버깅을 할 수 있도록 빠르게 실패하는 경우가 가장 많습니다. AssertionError:

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)

19
어설 션에 아무런 문제가 없기 때문에 (여기서는 아무 것도 만들지 않기 때문에) ValueError보다 좋은 경우입니다 AssertionError. 문제는 가치가 있습니다. 이 경우에 정말로 원한다면을 AssertionError쓰십시오 assert distance > 0, 'Distance must be positive'. 그러나 어설 션을 해제 할 수 있기 때문에 이런 식으로 오류를 확인해서는 안됩니다 ( python -O).
— 2 비트 연금술사

1
@ Two-BitAlchemist 좋은 지적입니다. 위의 간단한 예를 썼을 때 아이디어가 단순화되지 않았습니다. 많은 유사한 경우에 특정 값과 관련이없는 조건입니다. 그보다는 "제어 흐름이 여기에 와서는 안됩니다"라는 의미입니다.
— Evgeni Sergeev

2
@ Two-BitAlchemist Assertions를 끌 수 있습니다. 그렇지만 전혀 오류 확인에 사용해서는 안됩니까?
— Evgeni Sergeev

글쎄요. 내가 배포하려는 프로그램에서 유일한 오류 검사가되도록 두지 않을 것입니다. 다른 한편으로, 나는 동료들만을위한 프로그램을 만들어서 그들과 함께 운영한다면 그들 자신의 위험에 따라 사용한다고 말할 수 있었다 -O.
— 2 비트 연금술사

1
@ Two-BitAlchemist 저에게 어설 션의 역할은 자체적으로 오류 검사 (테스트가 필요한 것)가 아니라 특정 버그가 통과 할 수없는 코드 내에 펜스를 설정하는 것입니다. 따라서 버그를 추적하고 격리하는 것이 더 쉬워 져 불가피하게 발생할 수 있습니다. 테스트에는 많은 노력과 시간이 걸리지 만 이는 노력이 거의 들지 않는 좋은 습관입니다.
— Evgeni Sergeev

12

기존 답변을 먼저 읽으십시오. 이것은 단지 부록입니다.

인수를 사용하거나 사용하지 않고 예외를 발생시킬 수 있습니다.

예:

raise SystemExit

프로그램을 종료하지만 무슨 일이 있었는지 알고 싶을 수도 있습니다.

raise SystemExit("program exited")

프로그램을 닫기 전에 "프로그램 종료"를 stderr에 인쇄합니다.


2
이것이 OOP 패러다임에 반대하지 않습니까? 첫 번째 경우는 클래스 참조를, 두 번째 경우는 SystemExit 인스턴스를 던진다 고 가정합니다. 하지 않을까요 raise SystemExit()더 나은 선택을 할 수? 첫 번째 이유는 무엇입니까?
— burny

2

예외를 던지는 또 다른 방법은 assert입니다. assert를 사용하여 조건이 충족되지 않은 경우 조건이 충족되는지 확인할 수 있습니다 AssertionError. 자세한 내용은 여기 를 참조 하십시오 .

def avg(marks):
    assert len(marks) != 0,"List is empty."
    return sum(marks)/len(marks)

mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))

mark1 = []
print("Average of mark1:",avg(mark1))

2

참고 사항 : 일반적인 예외를 처리하고 싶을 때가 있습니다. 많은 파일을 처리하고 오류를 기록하는 경우 파일에 발생하는 모든 오류를 포착하고 기록한 다음 나머지 파일을 계속 처리 할 수 ​​있습니다. 이 경우

try:
    foo() 
except Exception as e:
    print(str(e)) # Print out handled error

좋은 방법을 차단하십시오. 그래도 raise특정 예외를 원하므로 그 의미를 알 수 있습니다.


0

파이썬의 raise 문을 배워야합니다. try 블록 안에 보관해야합니다. 예 -

try:
    raise TypeError            #remove TypeError by any other error if you want
except TypeError:
    print('TypeError raised')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.