수색…


소개

실행 중에 발견 된 오류를 예외라고하며 무조건 치명적이지 않습니다. 대부분의 예외는 프로그램에서 처리하지 않습니다. 선택한 예외를 처리하는 프로그램을 작성할 수 있습니다. 예외 및 예외 로직을 다루는 Python의 특정 기능이 있습니다. 또한 예외에는 풍부한 유형 계층 구조가 있으며, 모두 BaseException 유형을 상속합니다.

통사론

  • 예외를 제기하다
  • raise # 이미 발생 된 예외를 다시 발생시킵니다.
  • 설정 예외 원인 - 원인 # 파이썬 3에서 예외를 발생
  • None # Python 3에서 예외 발생 - 모든 예외 상황을 억제
  • 시험:
  • [예외 유형] [ 식별자로 ] 제외 :
  • 그밖에:
  • 마침내 :

예외 발생

코드에 조건이 발생하면 잘못된 매개 변수와 같이 처리 방법을 알 수 없으므로 적절한 예외가 발생해야합니다.

def even_the_odds(odds):
    if odds % 2 != 1:
        raise ValueError("Did not get an odd number")
    
    return odds + 1

예외 잡기

예외를 잡으려면 try...except: 를 사용하십시오. 다음과 같이 예외를 정확하게 지정해야합니다.

try:
    x = 5 / 0
except ZeroDivisionError as e:
    # `e` is the exception object
    print("Got a divide by zero! The exception was:", e)
    # handle exceptional case
    x = 0  
finally:
    print "The END"
    # it runs no matter what execute.

지정된 예외 클래스 (이 경우 ZeroDivisionError )는 해당 클래스 또는 예외의 하위 클래스에 해당하는 모든 예외를 포착합니다.

예를 들어 ZeroDivisionErrorArithmeticError 의 하위 클래스입니다.

>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)

따라서 다음과 같이 여전히 ZeroDivisionError catch합니다.

try:
    5 / 0
except ArithmeticError:
    print("Got arithmetic error")

마지막으로 정리 코드 실행하기

경우에 따라 일부 예외가 발생했는지 여부에 관계없이 무언가를 정리해야 할 수도 있습니다. 예를 들어 일부 리소스를 정리해야하는 경우가 있습니다.

try 절의 finally 블록은 예외가 발생했는지 여부에 관계없이 발생합니다.

resource = allocate_some_expensive_resource()
try:
    do_stuff(resource)
except SomeException as e:
    log_error(e)
    raise  # re-raise the error
finally:
    free_expensive_resource(resource)

이 패턴은 ( with 문을 사용하여) 컨텍스트 관리자로 처리하는 것이 더 효과적입니다.

예외 재발생

때로는 로깅 목적으로 검사 할 때 예외를 잡기를 원합니다. 검사가 끝나면 이전처럼 예외가 전파되기를 원합니다.

이 경우 단순히 매개 변수없이 raise 문을 사용하십시오.

try:
    5 / 0
except ZeroDivisionError:
    print("Got an error")
    raise

그래도 호출자 스택에있는 누군가가 예외를 잡아서 어떻게 든 처리 할 수 ​​있다는 것을 명심하십시오. 완성 된 결과물은 어떤 경우에도 발생하기 때문에이 경우 귀찮은 일이 될 수 있습니다 (걸려 넘어 지거나 걸리지 않음). 그러므로 다른 예외 상황을 제기하는 것이 더 좋은 생각 일 수 있습니다. 원래의 예외 상황뿐만 아니라 상황에 대한 의견도 들어 있습니다.

try:
    5 / 0
except ZeroDivisionError as e:
    raise ZeroDivisionError("Got an error", e)

그러나 이것은 예외 추적을 정확히이 raise 로 줄이는 단점이 있지만 인수가없는 raise 는 원래 예외 추적을 유지합니다.

파이썬 3에서는 raise - from 구문을 사용하여 원래 스택을 유지할 수 있습니다.

    raise ZeroDivisionError("Got an error") from e

레이즈가있는 체인 예외

예외를 처리하는 과정에서 또 다른 예외를 발생시킬 수 있습니다. 예를 들어, 파일에서 읽는 동안 IOErrorIOError 하면 응용 프로그램 별 오류를 발생시켜 라이브러리 사용자에게 제시 할 수 있습니다.

Python 3.x 3.0

예외 처리를 처리하는 방법을 보여주기 위해 예외를 연결할 수 있습니다.

>>> try:
    5 / 0
except ZeroDivisionError as e:
    raise ValueError("Division failed") from e

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: Division failed

예외 계층 구조

예외 처리는 예외 클래스의 상속 구조에 의해 결정되는 예외 계층 구조를 기반으로 발생합니다.

예를 들어 IOErrorOSError 는 모두 EnvironmentError 하위 클래스입니다. IOError 를 포착하는 코드는 OSError catch하지 않습니다. 그러나 EnvironmentError 를 포착하는 코드는 IOErrorOSError 모두 잡습니다.

기본 제공 예외의 계층 구조 :

파이썬 2.x 2.3
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |         +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
       +-- ImportWarning
       +-- UnicodeWarning
       +-- BytesWarning
Python 3.x 3.0
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

예외도 객체입니다.

예외는 내장 BaseException 을 상속 한 일반적인 Python 객체입니다. 파이썬 스크립트는 raise 문을 사용하여 실행을 중단함으로써 파이썬이 그 시점에서 호출 스택의 스택 추적과 예외 인스턴스의 표현을 인쇄하도록 할 수 있습니다. 예 :

>>> def failing_function():
...     raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in failing_function
ValueError: Example error!

'Example error!' 메시지가있는 ValueError'Example error!' 우리의 failing_function() 의해 제기되었는데, 그것은 interpreter에서 실행되었다.

호출 코드는 호출이 발생할 수있는 모든 유형의 예외를 처리하도록 선택할 수 있습니다.

>>> try:
...     failing_function()
... except ValueError:
...     print('Handled the error')
Handled the error

예외 처리 코드의 except... 부분에 예외 객체를 할당하여 예외 객체를 확보 할 수 있습니다.

>>> try:
...     failing_function()
... except ValueError as e:
...     print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)

내장 된 파이썬 예외의 전체 목록은 파이썬 문서에서 찾을 수 있습니다 : https://docs.python.org/3.5/library/exceptions.html . 다음은 계층 적으로 배열 된 전체 목록입니다. Exception Hierarchy .

사용자 정의 예외 유형 작성

Exception 에서 상속받은 클래스 만들기 :

class FooException(Exception):
    pass
try:
    raise FooException("insert description here")
except FooException:
    print("A FooException was raised.")

또는 다른 예외 유형 :

class NegativeError(ValueError):
      pass

def foo(x):
    # function that only accepts positive values of x
    if x < 0:
        raise NegativeError("Cannot process negative numbers")
    ...  # rest of function body
try:
    result = foo(int(input("Enter a positive integer: ")))  # raw_input in Python 2.x
except NegativeError:
    print("You entered a negative number!")
else:
    print("The result was " + str(result))

모든 걸 잡지 마!

모든 Exception 를 잡으려고하는 것은 종종 유혹적이지만 :

try:
    very_difficult_function()
except Exception:
    # log / try to reconnect / exit gratiously
finally:
    print "The END"
    # it runs no matter what execute.

또는 모든것 ( BaseExceptionException 포함하여 모든 자식 포함) :

try:
    even_more_difficult_function()
except:
    pass  # do whatever needed

대부분의 경우 나쁜 습관입니다. SystemExit , KeyboardInterruptMemoryError 와 같이 의도 한 것보다 더 많이 잡을 수 있습니다. 일반적으로 시스템 또는 논리 오류와 다르게 처리해야합니다. 또한 내부 코드가 잘못 수행 할 수있는 부분과 해당 상태에서 올바르게 복구하는 방법에 대한 명확한 이해가 없음을 의미합니다. 모든 오류를 잡는다면 어떤 오류가 발생했는지 또는 오류를 수정하는 방법을 알지 못할 것입니다.

이것은 더 일반적으로 '버그 마스킹'이라고하며이를 피해야합니다. 조용히 실패하거나 악화하는 대신 프로그램을 중단 시키십시오. 더 깊은 실행 수준에서는 실패합니다. (트랜잭션 시스템이라고 상상해보십시오)

일반적으로 이러한 구조는 프로그램의 매우 외부 수준에서 사용되며 버그를 수정하거나 오류를보다 구체적으로 처리 할 수 ​​있도록 오류의 세부 사항을 기록합니다.

여러 예외 잡기

여러 예외잡을 수 있는 몇 가지 방법이 있습니다.

첫 번째는 동일한 방식으로 catch하고 처리하려는 예외 유형의 튜플을 만드는 것입니다. 이 예제는 코드가 KeyErrorAttributeError 예외를 무시하도록합니다.

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except (KeyError, AttributeError) as e:
    print("A KeyError or an AttributeError exception has been caught.")

다른 예외를 여러 가지 방식으로 처리하려는 경우 각 유형에 대해 별도의 예외 블록을 제공 할 수 있습니다. 이 예제에서 우리는 여전히 KeyErrorAttributeError 를 잡았지만 다른 방식으로 예외를 처리합니다.

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except KeyError as e:
    print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
    print("An AttributeError has occurred. Exception message:", e)

예외 처리의 실제 예

사용자 입력

사용자가 입력을 통해 숫자를 input 한다고 가정 해보십시오. 입력이 숫자인지 확인하려고합니다. 이것을 위해 try / except 를 사용할 수 있습니다 :

Python 3.x 3.0
while True:
    try:
        nb = int(input('Enter a number: '))
        break
    except ValueError:
        print('This is not a number, try again.')

참고 : Python 2.x는 대신 raw_input 을 사용할 것입니다. 함수 input 은 Python 2.x에 존재하지만 다른 의미를가집니다. 위의 예에서, input 은 숫자로 평가되는 2 + 2 와 같은 표현식도 허용합니다.

입력을 정수로 변환 할 수 없으면 ValueError 가 발생합니다. 당신은 except 그것을 붙잡을 수 있습니다. 예외가 발생하지 않으면 break 는 루프 밖으로 점프합니다. 루프 다음에 nb 에는 정수가 포함됩니다.

사전

당신이 좋아하는 연속 정수의 목록이 반복되는 상상 range(n) , 그리고 당신이 사전의 목록이 d 당신은 어떤 특정 정수를 만날 때해야 할 일들에 대한 정보를 포함, 건너 뛰기 말할 d[i] 다음 사람을.

d = [{7: 3}, {25: 9}, {38: 5}]

for i in range(len(d)):
    do_stuff(i)
    try:
       dic = d[i]
       i += dic[i]
    except KeyError:
       i += 1

존재하지 않는 키에 대해 사전에서 값을 가져 오려고하면 KeyError 가 발생합니다.

그밖에

else 블록의 코드는 try 블록의 코드에 의해 예외가 발생하지 않은 경우에만 실행됩니다. 이것은 예외가 발생했을 때 실행하고 싶지 않은 코드가 있지만 해당 코드가 던진 예외를 포착하지 않으려는 경우에 유용합니다.

예 :

try:
    data = {1: 'one', 2: 'two'}
    print(data[1])
except KeyError as e:
    print('key not found')
else:
    raise ValueError()
# Output: one
# Output: ValueError

else: 이런 종류는 else: 절을 elif 시작하는 if 와 결합 될 수 없다는 것에주의하십시오. 아래에 들여 쓰기가 필요 if 다음과 같이 else: :

try:
    ...
except ...:
    ...
else:
    if ...:
        ...
    elif ...:
        ...
    else:
        ...


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow