はじめに
この実験では、Python で特定の型の例外かどうかをチェックする方法を学びます。これは、効果的なエラーハンドリングに不可欠なスキルです。この実験では、例外の階層構造を理解し、その知識を活用して特定の例外型を識別することに焦点を当てています。
この実験では、基底クラス BaseException とそのサブクラス(Exception など)から始まる Python の例外階層構造を探索する手順を案内します。異なる例外クラス間の関係を視覚化できるように、例外階層構造を出力する Python スクリプト exception_hierarchy.py を作成します。この理解を基に、後続の手順で isinstance() と直接のクラス比較を使用して例外の型をチェックします。
例外階層を理解する
このステップでは、Python の例外の階層構造について学びます。この階層構造を理解することは、効果的なエラーハンドリングに不可欠です。Python の例外は木構造で組織されており、最上位に基底クラスがあり、そこからより具体的な例外クラスが派生しています。
すべての例外の基底クラスは BaseException です。BaseException から直接派生するのは、Exception、GeneratorExit、KeyboardInterrupt、SystemExit です。Exception クラスは、プログラムが遭遇する可能性のあるエラーを示すほとんどの組み込み例外のスーパークラスです。
この階層構造を探索するための Python スクリプトを作成しましょう。
VS Code エディタを開きます。
~/projectディレクトリにexception_hierarchy.pyという名前の新しいファイルを作成します。~/project/exception_hierarchy.pyexception_hierarchy.pyファイルに以下のコードを追加します。def print_exception_hierarchy(exception_class, indent=0): """Prints the exception hierarchy starting from a given exception class.""" print(' ' * indent + str(exception_class)) for subclass in exception_class.__subclasses__(): print_exception_hierarchy(subclass, indent + 1) print("Exception Hierarchy:") print_exception_hierarchy(Exception)このスクリプトは、
Exceptionクラスから始まる例外の階層構造を出力する再帰関数print_exception_hierarchyを定義しています。ターミナルで以下のコマンドを使用してスクリプトを実行します。
python exception_hierarchy.pyこれにより、例外の階層構造が木構造でターミナルに出力されます。
出力例:
Exception Hierarchy: <class 'Exception'> <class 'ArithmeticError'> <class 'FloatingPointError'> <class 'OverflowError'> <class 'ZeroDivisionError'> <class 'decimal.DivisionByZero'> <class 'AssertionError'> <class 'AttributeError'> <class 'BufferError'> <class 'EOFError'> <class 'ImportError'> <class 'ModuleNotFoundError'> <class 'ZipImportError'> <class 'LookupError'> <class 'IndexError'> <class 'KeyError'> <class 'tracemalloc.DomainKey'> <class 'MemoryError'> <class 'NameError'> <class 'UnboundLocalError'> <class 'OSError'> <class 'BlockingIOError'> <class 'ChildProcessError'> <class 'ConnectionError'> <class 'BrokenPipeError'> <class 'ConnectionAbortedError'> <class 'ConnectionRefusedError'> <class 'ConnectionResetError'> <class 'FileExistsError'> <class 'FileNotFoundError'> <class 'InterruptedError'> <class 'InterruptedSystemCall'> <class 'IsADirectoryError'> <class 'NotADirectoryError'> <class 'PermissionError'> <class 'ProcessLookupError'> <class 'TimeoutError'> <class 'UnsupportedOperation'> <class 'itertools.Incomplete'> <class 'signal.ItimerError'> <class 'ReferenceError'> <class 'RuntimeError'> <class 'NotImplementedError'> <class 'asyncio.exceptions.IncompleteReadError'> <class 'zlib.error'> <class '_frozen_importlib._DeadlockError'> <class 'RecursionError'> <class 'StopAsyncIteration'> <class 'StopIteration'> <class 'SyntaxError'> <class 'IndentationError'> <class 'TabError'> <class 'SystemError'> <class 'TypeError'> <class 'ValueError'> <class 'UnicodeError'> <class 'UnicodeDecodeError'> <class 'UnicodeEncodeError'> <class 'UnicodeTranslateError'> <class 'Warning'> <class 'BytesWarning'> <class 'DeprecationWarning'> <class 'EncodingWarning'> <class 'FutureWarning'> <class 'ImportWarning'> <class 'PendingDeprecationWarning'> <class 'ResourceWarning'> <class 'RuntimeWarning'> <class 'SyntaxWarning'> <class 'UnicodeWarning'> <class 'UserWarning'>この出力は、
Exceptionを基底クラスとし、さまざまなサブクラスが特定のエラータイプを表す例外の階層構造を示しています。この階層構造を理解することで、適切な粒度レベルで例外を捕捉することができます。たとえば、ZeroDivisionErrorのような特定の例外を捕捉することも、ZeroDivisionErrorの親であるArithmeticErrorのようなより一般的な例外を捕捉することもできます。
例外に対して isinstance() を使用する
このステップでは、isinstance() 関数を使用して、例外が特定のクラスまたはクラスのタプルのインスタンスであるかどうかをチェックする方法を学びます。これは、さまざまなタイプの例外を柔軟に処理するのに役立ちます。
isinstance() 関数は 2 つの引数を取ります。オブジェクトと classinfo です。オブジェクトが classinfo またはそのサブクラスのインスタンスである場合は True を返し、そうでない場合は False を返します。
例外に対する isinstance() の使用方法を示す Python スクリプトを作成しましょう。
VS Code エディタを開きます。
~/projectディレクトリにisinstance_exception.pyという名前の新しいファイルを作成します。~/project/isinstance_exception.pyisinstance_exception.pyファイルに以下のコードを追加します。try: result = 10 / 0 except Exception as e: if isinstance(e, ZeroDivisionError): print("Caught a ZeroDivisionError!") elif isinstance(e, ArithmeticError): print("Caught an ArithmeticError!") else: print("Caught some other exception!") print("Program continues...")このスクリプトでは、10 を 0 で割ろうとしており、これにより
ZeroDivisionErrorが発生します。その後、例外を捕捉し、isinstance()を使用して、それがZeroDivisionErrorまたはArithmeticErrorのインスタンスであるかどうかをチェックします。ターミナルで以下のコマンドを使用してスクリプトを実行します。
python isinstance_exception.pyこれにより、ターミナルに "Caught a ZeroDivisionError!" と表示されます。
出力例:
Caught a ZeroDivisionError! Program continues...この出力は、
isinstance()関数が例外をZeroDivisionErrorのインスタンスとして正しく識別したことを示しています。ZeroDivisionErrorはArithmeticErrorのサブクラスであるため、最初のif条件が満たされ、対応するメッセージが表示されます。次に、より一般的な例外を捕捉するようにスクリプトを変更しましょう。
isinstance_exception.pyファイルを以下のように変更します。try: result = int("abc") except Exception as e: if isinstance(e, ZeroDivisionError): print("Caught a ZeroDivisionError!") elif isinstance(e, ValueError): print("Caught a ValueError!") elif isinstance(e, ArithmeticError): print("Caught an ArithmeticError!") else: print("Caught some other exception!") print("Program continues...")この変更後のスクリプトでは、文字列 "abc" を整数に変換しようとしており、これにより
ValueErrorが発生します。同じコマンドを使用してスクリプトを再度実行します。
python isinstance_exception.pyこれにより、ターミナルに "Caught a ValueError!" と表示されます。
出力例:
Caught a ValueError! Program continues...この出力は、
isinstance()を使用して異なるタイプの例外を区別し、それに応じて処理できることを示しています。
例外クラスでチェックする
このステップでは、except ブロック内で直接特定の例外クラスをチェックする方法を学びます。これは、isinstance() を使用するよりも直接的で、多くの場合、例外を処理するより明確な方法です。
except ExceptionType as e: を使用すると、Python に対して ExceptionType 型またはそのサブクラスの例外のみを捕捉するよう指示しています。
これを実証する Python スクリプトを作成しましょう。
VS Code エディタを開きます。
~/projectディレクトリにexception_classes.pyという名前の新しいファイルを作成します。~/project/exception_classes.pyexception_classes.pyファイルに以下のコードを追加します。try: result = 10 / 0 except ZeroDivisionError as e: print("Caught a ZeroDivisionError:", e) except ArithmeticError as e: print("Caught an ArithmeticError:", e) except Exception as e: print("Caught some other exception:", e) print("Program continues...")このスクリプトでは、10 を 0 で割ろうとしており、これにより
ZeroDivisionErrorが発生します。3 つのexceptブロックがあります。ZeroDivisionError用、ArithmeticError用、そしてException用です。ターミナルで以下のコマンドを使用してスクリプトを実行します。
python exception_classes.pyこれにより、ターミナルに "Caught a ZeroDivisionError: division by zero" と表示されます。
出力例:
Caught a ZeroDivisionError: division by zero Program continues...この出力は、
ZeroDivisionErrorが最初のexceptブロックで捕捉されたことを示しています。次に、別の例外を発生させるようにスクリプトを変更しましょう。
exception_classes.pyファイルを以下のように変更します。try: result = int("abc") except ZeroDivisionError as e: print("Caught a ZeroDivisionError:", e) except ValueError as e: print("Caught a ValueError:", e) except ArithmeticError as e: print("Caught an ArithmeticError:", e) except Exception as e: print("Caught some other exception:", e) print("Program continues...")この変更後のスクリプトでは、文字列 "abc" を整数に変換しようとしており、これにより
ValueErrorが発生します。同じコマンドを使用してスクリプトを再度実行します。
python exception_classes.pyこれにより、ターミナルに "Caught a ValueError: invalid literal for int() with base 10: 'abc'" と表示されます。
出力例:
Caught a ValueError: invalid literal for int() with base 10: 'abc' Program continues...この出力は、
ValueErrorが 2 番目のexceptブロックで捕捉されたことを示しています。exceptブロック内で直接例外クラスを指定することで、さまざまなタイプの例外を明確かつ整理された方法で処理することができます。このアプローチは、単純な例外処理において、isinstance()を使用するよりも一般的に好まれます。
まとめ
この実験では、Python の例外階層について調査しました。これは、効果的なエラー処理に不可欠です。例外は、BaseException を基底クラスとし、ほとんどの組み込み例外のスーパークラスとして Exception を持つ木構造で整理されていることを学びました。
exception_hierarchy.py という Python スクリプトを作成し、Exception クラスから始まる例外階層を出力しました。このスクリプトを実行することで、例外の木構造とそれらの関係を観察し、Python で例外がどのように整理されているかをより深く理解することができました。



