Skip to content

Python:exceptions

Python에서, 모든 예외는 BaseException 에서 파생된 클래스의 인스턴스여야 합니다. 특정 클래스를 언급하는 except 절을 갖는 try 문에서, 그 절은 그 클래스에서 파생된 모든 예외 클래스를 처리합니다 (하지만 그것 이 계승하는 예외 클래스는 처리하지 않습니다). 서브 클래싱을 통해 관련되지 않은 두 개의 예외 클래스는 같은 이름을 갖는다 할지라도 결코 등등하게 취급되지 않습니다.

How to use

  • raise는 에러를 발생시키기 위해 사용하는 명령어 이다.
  • try: ... except: ...는 가장 기본적인 Exception handling 구문이다.

raise from

파이썬 except 블록에서 예외를 처리하는 도중에 또 다른 예외가 발생할 수 있다. 이 때 예외를 처리하는 도중 발생한 에러가 어떤 예외로부터 파생되었는지 알고 싶다면, raise from을 사용하면 된다.

import json

def load_json_key(data, key):
    try:
        result_dict = json.loads(data) # ValueError 발생할 수 있음.
    except ValueError as e:
        raise KeyError(key) from e
    else:
        return result_dict[key] # KeyError 발생 가능

load_json_key('{"foo": "bar"', 'foo')

StackOverflow 에서 관련 내용을 찾을 수 있었다. from 절을 사용하면 발생한 예외의 __cause__ 속성이 설정되어 에러 메시지 출력 시 "directly caused by" 를 통해 어떤 예외로부터 파생된 예외인지 알 수 있다는 것이다. 만약 from 절을 사용하지 않으면 __cause__ 대신 __context__ 속성이 설정된다. 그렇기 때문에 해당 예외가 어떤 상황에서 발생했는지를 알려주기 위해 에러 메시지 출력 시 "during handling ~ happened"와 같은 문구가 나오는 것이다.

만약 이 모든 메시지를 보는 것이 번거롭다면, raise … from None을 사용하면 된다. 처음 발생한 예외만 에러 메시지로 출력된다.

List of exception

  • NotImplementedError: 구현체가 존재하지 않음.

Handling Exceptions

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as e:
    print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

User-defined Exceptions

class MyError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

예외 계층 구조

내장 예외의 클래스 계층 구조는 다음과 같습니다:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- 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

개인적으로 사용하는 Exception 규칙

다음의 규칙을 따른다.

  • 가급적 내장 예외를 사용한다.
  • 가급적 구체적인 에러 메시지를 적는다.
  • 문장 마침표는 사용하지 않는다.
  • 개행은 가급적 사용하지 않는다. (에러 내용은 가급적 한줄로 요약)
  • BaseException 은 빌트인이다. 따라서 커스텀 예외는 Exception 을 상속받는다. 상속 계층 구조를 참조하여 자식 클래스로부터 직접 상속받아도 OK.

몇 가지 케이스:

  • 값이 잘못된 경우 (EmptyArgument, IllegalArgument, Encoding, Decoding, etc): ValueError
    • 파싱에러의 경우 SyntaxError 사용금지. 이 에러는 파이선 문법에 한정된다.
  • 인덱스가 잘못된 경우 (OutOfIndex, etc): IndexError
  • 키가 잘못된 경우: KeyError
  • 타입이 잘못된 경우: TypeError
  • 종합적인 타임아웃: TimeoutError
  • 구현되지 않음: NotImplementedError
  • 그 밖의 상황: RuntimeError
    • 상태와 관련된 에러 (Exists, NotExists, NotReadyState, AlreadyState, IllegalState, etc)는 모두 RuntimeError 이다.
    • 찾을 수 없음 (NotFound) 에러도 RuntimeError 이다.
      • 단, 파일을 찾을수 없다면 FileNotFoundError 를 사용해야 한다.
    • 초기화 되지 않음 (NotInitialized) 에러도 RuntimeError 이다.
      • LookupError는 (매핑 또는 시퀀스에 사용된) 키나 인덱스가 잘못되었을 때 사용된다.
  • 권한(읽기/쓰기/실행과 같은)에러는 PermissionError

See also

Favorite site

References


  1. Jump_to_Python_-_Exception.pdf