Pythonでエラーを怖れない! 組み込み例外のしくみと完全攻略


そこで重要となるのが、組み込み例外です。Pythonは、様々な状況で発生する可能性のあるエラーを網羅した例外クラスを標準で提供しており、これらを適切に処理することで、プログラムの安定性と信頼性を向上させることができます。

組み込み例外の仕組み

Pythonの全ての例外は、BaseExceptionと呼ばれる基底クラスから派生しています。そして、この基底クラスから様々な派生クラスが階層構造を成しています。

各派生クラスは、特定の種類のエラーに対応しており、それぞれ固有の属性やメソッドを提供します。例えば、ZeroDivisionError例外は0で除算しようとすると発生し、NameError例外は存在しない変数を参照しようとすると発生します。

例外処理の基本

Pythonでは、try-except構文を用いて例外処理を行います。この構文は以下の通りです。

try:
    # 実行したい処理
except Exception as e:
    # 例外が発生した場合の処理

上記のコードでは、tryブロック内で記述された処理が実行されます。もしその処理中に例外が発生した場合、exceptブロック内の処理が実行されます。asキーワードを用いることで、例外オブジェクトを変数に格納し、詳細な情報にアクセスすることができます。

主な組み込み例外

  • OSError
    オペレーティングシステム関連のエラーが発生した場合に発生します。
  • FileNotFoundError
    ファイルが見つからない場合に発生します。
  • KeyError
    辞書に存在しないキーを参照しようとすると発生します。
  • IndexError
    リストなどのインデックスが範囲外の場合に発生します。
  • AttributeError
    存在しない属性を参照しようとすると発生します。
  • TypeError
    型が不適切な操作を行おうとすると発生します。
  • NameError
    存在しない変数を参照しようとすると発生します。
  • ZeroDivisionError
    0で除算しようとすると発生します。
  • デバッグツールを活用する
    Pythonには、pdbなどのデバッグツールが用意されており、例外発生時の状況を詳細に解析することができます。
  • デフォルト例外ハンドラーを使用する
    想定外の例外が発生した場合に備えて、デフォルトの例外ハンドラーを用意しておきましょう。
  • 適切な例外を捕捉する
    具体的な例外クラスを捕捉することで、より詳細な処理を行うことができます。


特定の例外を捕捉

try:
    x = 10 / 0
except ZeroDivisionError as e:
    print("0で除算することはできません:", e)
else:
    print("計算結果:", x)

このコードでは、10 / 0という0除算を実行しようとします。これはZeroDivisionError例外を引き起こすため、exceptブロック内の処理が実行され、エラーメッセージが表示されます。

複数の例外を捕捉

try:
    open("nonexistent_file.txt")
except (FileNotFoundError, PermissionError) as e:
    print("ファイル操作に失敗しました:", e)

例外を再送出

def divide(x, y):
    try:
        return x / y
    except ZeroDivisionError:
        raise  # 上位レイヤーに例外を再送出

try:
    result = divide(10, 0)
except ZeroDivisionError as e:
    print("0で除算することはできません:", e)

このコードでは、divide関数は0で除算しようとするとZeroDivisionError例外を再送出します。try-except構文で捕捉された例外は、さらに上位のtry-except構文に伝播されます。

カスタム例外の作成

class MyError(Exception):
    pass

def check_value(x):
    if x < 0:
        raise MyError("値が負です")

try:
    check_value(-1)
except MyError as e:
    print("エラー:", e)

このコードでは、MyErrorというカスタム例外クラスを作成しています。check_value関数は、引数が負の場合はMyError例外を発生させます。

try:
    f = open("myfile.txt", "w")
    try:
        f.write("Hello, world!")
    finally:
        f.close()
except Exception as e:
    print("エラーが発生しました:", e)

このコードでは、finallyブロックを使用して、tryブロック内で発生した例外に関わらず、ファイルを確実に閉じるようにしています。



以下に、Exceptionの代替方法として検討すべき3つの方法をご紹介します。

特定の例外を捕捉する

最も一般的な代替方法は、特定の例外クラスを捕捉することです。例えば、ZeroDivisionErrorNameErrorKeyErrorなどのように、発生する可能性が高い例外を個別に捕捉することで、より具体的な処理を行うことができます。

try:
    x = 10 / 0
except ZeroDivisionError:
    print("0で除算することはできません")
except NameError as e:
    print("存在しない変数を参照しました:", e.name)

このコードでは、ZeroDivisionErrorNameErrorという2つの例外を個別に捕捉しています。それぞれの場合に、適切なエラーメッセージを表示します。

カスタム例外を作成する

より複雑なエラー処理が必要な場合は、カスタム例外を作成することができます。これにより、独自のエラーメッセージや処理を定義することができます。

class MyError(Exception):
    def __init__(self, message):
        super().__init__(message)

def check_value(x):
    if x < 0:
        raise MyError("値が負です")

try:
    check_value(-1)
except MyError as e:
    print("カスタムエラー:", e.message)

このコードでは、MyErrorというカスタム例外クラスを作成しています。この例外は、check_value関数内で引数が負の場合は発生します。

例外が発生した場合、常に例外を再スローする必要はありません。特に、予期されるエラーの場合や、デバッグ目的の場合には、ログを記録するだけで十分な場合があります。

try:
    f = open("myfile.txt")
    try:
        content = f.read()
    finally:
        f.close()
except Exception as e:
    logging.error("ファイル処理中にエラーが発生しました:", e)