Skip to content
Search

Python:exceptions

lastmod 2022-02-18created 2020-07-2615 edits

In Python, all exceptions must be instances of a class that derives from BaseException. In a try statement with an except clause that mentions a particular class, that clause also handles any exception classes derived from that class (but not exception classes from which it is derived). Two exception classes that are not related via subclassing are never equivalent, even if they have the same name.

How to use

  • raise is the statement used to raise an error.
  • try: ... except: ... is the most basic Exception handling statement.

raise from

In a Python except block, another exception can be raised while handling an exception. If you want to show which exception the error raised during handling was derived from, use 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')

I found the relevant explanation on StackOverflow. With the from clause, the __cause__ attribute of the raised exception is set, so the error message shows "directly caused by" and you can see which exception it was derived from. Without the from clause, the __context__ attribute is set instead of __cause__. That is why the error message shows a phrase like "during handling ~ happened" to tell you the situation in which the exception occurred.

If seeing all these messages is a hassle, use raise … from None. Only the first exception raised is printed in the error message.

List of exception

  • NotImplementedError: no implementation exists.

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)

Exception hierarchy

The class hierarchy for built-in exceptions is:

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

My personal Exception rules

I follow these rules.

  • Use built-in exceptions whenever possible.
  • Write error messages that are as specific as possible.
  • Do not use a sentence-ending period.
  • Avoid line breaks where possible. (Summarize the error in one line where possible)
  • BaseException is built-in. So custom exceptions inherit from Exception. Inheriting directly from a child class, per the inheritance hierarchy, is also OK.

Some cases:

  • Wrong value (EmptyArgument, IllegalArgument, Encoding, Decoding, etc): ValueError
    • Do not use SyntaxError for parsing errors. That error is limited to Python syntax.
  • Wrong index (OutOfIndex, etc): IndexError
  • Wrong key: KeyError
  • Wrong type: TypeError
  • General timeout: TimeoutError
  • Not implemented: NotImplementedError
  • Other situations: RuntimeError
    • State-related errors (Exists, NotExists, NotReadyState, AlreadyState, IllegalState, etc) are all RuntimeError.
    • Not found (NotFound) errors are also RuntimeError.
      • However, if a file cannot be found, use FileNotFoundError.
    • Not initialized (NotInitialized) errors are also RuntimeError.
      • LookupError is used when a key or index (used on a mapping or sequence) is invalid.
  • Permission errors (such as read/write/execute) are PermissionError

See also

Favorite site

References


  1. Jump_to_Python_-_Exception.pdf ↩

author Zer0 sitemap