파이썬에서 예외를 수동으로 발생 (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.