Python/例外処理

出典: フリー教科書『ウィキブックス(Wikibooks)』

例外処理(れいがいしょり、exception handling)とは、プログラム実行中に予期せぬ異常が発生した場合に、通常の実行フローを中断し、エラーメッセージの表示や適切な処理を行うプログラムの手法です。

raise[編集]

raise文は、プログラムの実行中に発生したエラーや問題を示し、その場で例外を引き起こします。例えば、条件に合致しない場合や予期せぬ状況であれば、raise文を使って例外を発生させることができます。

def reduce(array, callback, initialValue):
    if not callable(callback):
        raise ValueError(str(callback) + " is not a function")
    # ...

reduce([], None, None)
実行結果
Traceback (most recent call last):
  File "Main.py", line 6, in <module>
    reduce([], None, None) 
  File "Main.py", line 3, in reduce
    raise ValueError(str(callback) + " is not a function") 
ValueError: None is not a function

後述のtry/except ブロックなしで raise を実行すると、エラーが現在のコンテキストから伝播し、エラーが発生したポイントからコードの実行が停止されます。これにより、通常の実行フローが中断され、エラーがコンソールに表示されたり、上位の呼び出し元でエラーがキャッチされるまで、エラーが伝播します。

try節とexcept節[編集]

tryexceptは、Pythonにおける例外処理を行うための構文です。tryブロック内のコードを実行し、もし例外が発生した場合に備えてそれをキャッチするためのものです。

基本的な構文は以下のようになります。

try:
    # ここに例外が発生する可能性のあるコードを記述する
    # 例外が発生した場合、次の行からの実行は中断される
    # 例外が発生しなければ、exceptブロックは実行されない
except エラーの種類 as エラーオブジェクト:
    # 例外が発生した場合に行う処理を記述する
    # エラーの種類に応じて処理を変えることができる
finally:
    # 必要に応じて、例外の発生に関わらず最後に実行される処理を記述する

例外が発生する可能性があるコードをtryブロックに記述し、もし例外が発生した場合、その種類に応じたexceptブロックが実行されます。exceptブロックでは例外の種類を指定し、その例外が発生した際に実行するコードを記述します。

例えば:

try:
    result = 10 / 0  # ゼロ除算の例外が発生する可能性があるコード
except ZeroDivisionError as e:
    print("エラーが発生しました:", e)

この例では、ゼロ除算の例外が発生する可能性があるため、tryブロックで計算を行っています。もしゼロ除算のエラーが発生すれば、exceptブロックが実行され、エラーメッセージが表示されます。

else節とfinally節[編集]

Pythonの例外処理には、tryexceptに加えてelse節とfinally節もあります。else節は、tryブロック内で例外が発生しなかった場合に実行される部分です。

基本的な構文は次のようになります:

try:
    # 例外が発生する可能性のあるコード
except エラーの種類 as エラーオブジェクト:
    # 例外が発生した場合の処理
else:
    # 例外が発生しなかった場合の処理
finally:
    # 例外の有無に関わらず最後に実行される処理

else節は、tryブロック内で例外が発生せず、正常に処理が完了した場合に実行されます。例外が発生した場合はexceptブロックが実行され、例外が発生しなかった場合はelseブロックが実行されるという流れです。

例えば:

try:
    result = 10 / 2  # 例外が発生しないようなコード
except ZeroDivisionError as e:
    print("ゼロ除算エラー:", e)
else:
    print("計算結果:", result)
finally:
    print("処理が完了しました")

この例では、tryブロック内でゼロ除算が行われていないため、exceptブロックは実行されず、代わりにelseブロックが実行され、計算結果が表示されます。最後にfinallyブロックが実行され、"処理が完了しました"というメッセージが表示されます。

return と finally[編集]

return と finally
def div(n, d) :
    try :
        return n / d
    except Exception as e:
        print(e)
    finally :
        print("div(%s, %s) -- finally" % (n, d))

print("div(1, 2) = %s" % div(1, 2))
print("div(1, 0) = %s" % div(1, 0))
print("div(0, 0) = %s" % div(0, 0))
実行結果
div(1, 2) -- finally
div(1, 2) = 0.5
division by zero
div(1, 0) -- finally
div(1, 0) = None
division by zero
div(0, 0) -- finally
div(0, 0) = None
try文にfinally節を持つ言語では「tryブロックで例外を出さずのreturn文に達したとき、finally節を実行するか?」が問題になります。
Puthonでは、return文に達してもfinally節が実行されます。

例外の場合わけ[編集]

Pythonにおける例外の場合分けは、tryexceptを使用して行います。exceptブロックは、特定の例外が発生した場合にそれをキャッチして処理するために使用されます。また、exceptブロックは複数指定することもできます。

例えば:

try:
    result = 10 / 0  # 例外が発生する可能性のあるコード
except ZeroDivisionError as e:
    print("ゼロ除算エラー:", e)
except TypeError as e:
    print("型エラーが発生しました:", e)
except Exception as e:
    print("予期せぬエラーが発生しました:", e)

上記の例では、tryブロック内でゼロ除算が行われています。しかし、ZeroDivisionError以外のエラーが発生する可能性もあるため、複数のexceptブロックで異なる例外をキャッチするようにしています。exceptブロックの最後にExceptionを指定することで、すべての予期せぬ例外をキャッチすることができます。

また、exceptブロックで例外をキャッチするだけでなく、例外の情報を取得したり、適切な処理を行ったりすることもできます。

try:
    num = int(input("数字を入力してください: "))
    result = 10 / num
    print("計算結果:", result)
except ValueError:
    print("無効な値が入力されました。整数を入力してください。")
except ZeroDivisionError:
    print("ゼロで除算することはできません。")
else:
    print("正常に計算が完了しました。")
finally:
    print("プログラムの実行が終了しました。")

この例では、ユーザーから整数の入力を受け取り、その入力に応じて計算を行います。ValueErrorZeroDivisionErrorなどの特定の例外に応じてメッセージを表示し、それぞれの状況に適した対処を行っています。elseブロックは例外が発生しなかった場合に実行され、finallyブロックは最後に必ず実行されます。

組込み例外一覧[編集]

__builtins__ の要素のうち BaseExceptionのサブクラスを例外とし、例外と例外の __doc__ を表にしました。

組込み例外一覧
#print(issubclass(ValueError, Exception))
ex = []
for k in vars(__builtins__):
    try:
        if eval(f"issubclass({k}, BaseException)"):
            ex.append(k)
    except TypeError:
        pass

print(f"""\
{{| class=wikitable
|+ 組込み例外
!例外!!__doc__\
""")

for k in sorted(ex):
    print(f"""\
|-
! {k}
| {eval(f"{k}.__doc__")}\
""")

print("|}")

このコードは、Pythonの__builtins__モジュール内の組み込み例外クラスを取得しています。具体的には、BaseExceptionクラスを継承している例外クラスを収集してリストに追加しています。

以下、このコードの動作を詳しく説明します。

  1. __builtins__モジュールにはPythonの組み込み関数や組み込み例外が含まれています。
  2. vars(__builtins__)を使うことで、__builtins__モジュール内の変数(関数やクラスなど)の辞書を取得できます。
  3. ループを使ってvars(__builtins__)内の各要素(k)に対して処理を行います。
  4. issubclass()関数は、1つのクラスが別のクラスのサブクラスであるかどうかを確認します。
  5. eval()関数を使って文字列をPythonコードとして評価し、issubclass()を使ってBaseExceptionクラスを継承しているかどうかを確認します。
  6. BaseExceptionクラスを継承している場合、その例外クラス名をリストexに追加します。
  7. tryブロック内でTypeErrorが発生した場合(例外クラスがissubclass()に適合しない場合)、exceptブロックでpassを使って何もせずにスキップします。

つまり、このコードは組み込みの例外クラスを調べ、BaseExceptionクラスを継承しているものをリストexに追加するものです。例外ハンドリングや特定の例外クラスに対する処理を行う際に、組み込みの例外クラスを動的に取得する際に役立ちます。

組込み例外
例外 __doc__
ArithmeticError Base class for arithmetic errors.
AssertionError Assertion failed.
AttributeError Attribute not found.
BaseException Common base class for all exceptions
BlockingIOError I/O operation would block.
BrokenPipeError Broken pipe.
BufferError Buffer error.
BytesWarning Base class for warnings about bytes and buffer related problems, mostly

related to conversion from str or comparing to str.

ChildProcessError Child process error.
ConnectionAbortedError Connection aborted.
ConnectionError Connection error.
ConnectionRefusedError Connection refused.
ConnectionResetError Connection reset.
DeprecationWarning Base class for warnings about deprecated features.
EOFError Read beyond end of file.
EnvironmentError Base class for I/O related errors.
Exception Common base class for all non-exit exceptions.
FileExistsError File already exists.
FileNotFoundError File not found.
FloatingPointError Floating point operation failed.
FutureWarning Base class for warnings about constructs that will change semantically

in the future.

GeneratorExit Request that a generator exit.
IOError Base class for I/O related errors.
ImportError Import can't find module, or can't find name in module.
ImportWarning Base class for warnings about probable mistakes in module imports
IndentationError Improper indentation.
IndexError Sequence index out of range.
InterruptedError Interrupted by signal.
IsADirectoryError Operation doesn't work on directories.
KeyError Mapping key not found.
KeyboardInterrupt Program interrupted by user.
LookupError Base class for lookup errors.
MemoryError Out of memory.
ModuleNotFoundError Module not found.
NameError Name not found globally.
NotADirectoryError Operation only works on directories.
NotImplementedError Method or function hasn't been implemented yet.
OSError Base class for I/O related errors.
OverflowError Result too large to be represented.
PendingDeprecationWarning Base class for warnings about features which will be deprecated

in the future.

PermissionError Not enough permissions.
ProcessLookupError Process not found.
RecursionError Recursion limit exceeded.
ReferenceError Weak ref proxy used after referent went away.
ResourceWarning Base class for warnings about resource usage.
RuntimeError Unspecified run-time error.
RuntimeWarning Base class for warnings about dubious runtime behavior.
StopAsyncIteration Signal the end from iterator.__anext__().
StopIteration Signal the end from iterator.__next__().
SyntaxError Invalid syntax.
SyntaxWarning Base class for warnings about dubious syntax.
SystemError Internal error in the Python interpreter.

Please report this to the Python maintainer, along with the traceback, the Python version, and the hardware/OS platform and version.

SystemExit Request to exit from the interpreter.
TabError Improper mixture of spaces and tabs.
TimeoutError Timeout expired.
TypeError Inappropriate argument type.
UnboundLocalError Local name referenced but not bound to a value.
UnicodeDecodeError Unicode decoding error.
UnicodeEncodeError Unicode encoding error.
UnicodeError Unicode related error.
UnicodeTranslateError Unicode translation error.
UnicodeWarning Base class for warnings about Unicode related problems, mostly

related to conversion problems.

UserWarning Base class for warnings generated by user code.
ValueError Inappropriate argument value (of correct type).
Warning Base class for warning categories.
ZeroDivisionError Second argument to a division or modulo operation was zero.