Python で例外が捕捉されたかどうかを確認する方法

PythonPythonBeginner
今すぐ練習

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、Python で異なる手法を使って例外が捕捉されたかどうかを確認する方法を学びます。この実験は、堅牢で信頼性の高い Python コードを書く上で重要な要素である例外処理に焦点を当てています。

この実験では、try...except ブロックを使って ZeroDivisionError のようなエラーを適切に処理する例外処理の流れを理解する手順を案内します。except ブロック内でフラグを設定して例外が捕捉されたことを示す方法を学びます。最後に、より制御された例外処理のためにコンテキストマネージャを使用する概念を紹介します。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/ErrorandExceptionHandlingGroup(["Error and Exception Handling"]) python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/ControlFlowGroup -.-> python/conditional_statements("Conditional Statements") python/ErrorandExceptionHandlingGroup -.-> python/catching_exceptions("Catching Exceptions") python/ErrorandExceptionHandlingGroup -.-> python/raising_exceptions("Raising Exceptions") python/FileHandlingGroup -.-> python/file_opening_closing("Opening and Closing Files") python/FileHandlingGroup -.-> python/file_operations("File Operations") python/AdvancedTopicsGroup -.-> python/context_managers("Context Managers") subgraph Lab Skills python/conditional_statements -.-> lab-559610{{"Python で例外が捕捉されたかどうかを確認する方法"}} python/catching_exceptions -.-> lab-559610{{"Python で例外が捕捉されたかどうかを確認する方法"}} python/raising_exceptions -.-> lab-559610{{"Python で例外が捕捉されたかどうかを確認する方法"}} python/file_opening_closing -.-> lab-559610{{"Python で例外が捕捉されたかどうかを確認する方法"}} python/file_operations -.-> lab-559610{{"Python で例外が捕捉されたかどうかを確認する方法"}} python/context_managers -.-> lab-559610{{"Python で例外が捕捉されたかどうかを確認する方法"}} end

例外処理の流れを学ぶ

このステップでは、Python の例外処理について学びます。例外処理は、堅牢で信頼性の高いコードを書く上で重要な部分です。これにより、プログラムの実行中に発生する可能性のあるエラーを適切に処理し、プログラムのクラッシュを防ぎ、よりユーザーフレンドリーな体験を提供することができます。

簡単な例から始めましょう。2 つの数を除算したいが、2 番目の数が 0 になる可能性があるとします。0 で除算することは未定義の操作であり、Python では ZeroDivisionError が発生します。

  1. LabEx 環境で VS Code エディタを開きます。

  2. ~/project ディレクトリに division.py という名前の新しいファイルを作成します。

    touch ~/project/division.py
  3. division.py ファイルを編集し、以下のコードを追加します。

    ## division.py
    numerator = 10
    denominator = 0
    
    result = numerator / denominator
    
    print(result)
  4. python コマンドを使用してスクリプトを実行します。

    python ~/project/division.py

次のようなエラーメッセージが表示されます。

Traceback (most recent call last):
  File "/home/labex/project/division.py", line 4, in <module>
    result = numerator / denominator
ZeroDivisionError: division by zero

このエラーメッセージは、0 で除算しようとしたために ZeroDivisionError が発生したことを示しています。例外処理がない場合、プログラムは突然終了します。

では、例外処理を使用してこのエラーを適切に処理しましょう。

  1. division.py ファイルを変更して、try...except ブロックを追加します。

    ## division.py
    numerator = 10
    denominator = 0
    
    try:
        result = numerator / denominator
        print(result)
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")

このコードでは、try ブロックに例外が発生する可能性のあるコードが含まれています。try ブロック内で ZeroDivisionError が発生した場合、except ブロック内のコードが実行されます。

  1. スクリプトを再度実行します。

    python ~/project/division.py

これで、プログラムはクラッシュする代わりに、次のように出力されます。

Error: Cannot divide by zero.

これは、例外処理の基本構造を示しています。

  • try ブロックは、例外が発生する可能性のあるコードを囲みます。
  • except ブロックは、捕捉する例外のタイプと、その例外が発生した場合に実行するコードを指定します。

複数の except ブロックを使用して、複数のタイプの例外を捕捉することもできます。

## division.py
numerator = 10
denominator = "abc"

try:
    result = numerator / int(denominator)
    print(result)
except ZeroDivisionError:
    print("Error: Cannot divide by zero.")
except ValueError:
    print("Error: Invalid input. Please enter a number.")

この例では、ValueError 例外ハンドラを追加しています。denominator を整数に変換できない場合(たとえば、"abc" のような文字列の場合)、ValueError が発生し、対応する except ブロックが実行されます。

スクリプトを実行します。

python ~/project/division.py

出力:

Error: Invalid input. Please enter a number.

例外処理により、潜在的なエラーを予測して処理することで、より堅牢でユーザーフレンドリーなプログラムを作成することができます。

except ブロックでフラグを設定する

このステップでは、except ブロック内でフラグを使用して、例外が発生したかどうかに基づいてプログラムの流れを制御する方法を学びます。これは、try ブロックの結果に応じて異なるアクションを実行する必要がある場合に便利な手法です。

前の例を基に、除算が成功した場合にのみ数の逆数を計算したいとします。除算が成功したかどうかを示すフラグを使用し、それに応じて逆数を計算することができます。

  1. LabEx 環境で VS Code エディタを開きます。

  2. ~/project ディレクトリの division.py ファイルを変更して、フラグを追加します。

    ## division.py
    numerator = 10
    denominator = 2
    success = True  ## Initialize the flag to True
    
    try:
        result = numerator / denominator
        print("Result of division:", result)
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        success = False  ## Set the flag to False if an error occurs
    except ValueError:
        print("Error: Invalid input. Please enter a number.")
        success = False ## Set the flag to False if an error occurs
    else:
        print("No exception occurred.")
    
    if success:
        try:
            reciprocal = 1 / result
            print("Reciprocal:", reciprocal)
        except ZeroDivisionError:
            print("Cannot calculate reciprocal of zero.")
    else:
        print("Reciprocal calculation skipped due to error.")

このコードでは、以下のことを行っています。

  • try ブロックの前に success という名前のフラグを True に初期化します。
  • ZeroDivisionError または ValueError が発生した場合、対応する except ブロック内で success フラグを False に設定します。
  • try...except ブロックの後で、success フラグの値を確認します。まだ True であれば、例外が発生していないことを意味し、安全に逆数を計算することができます。そうでない場合は、逆数の計算をスキップします。
  • try ブロックで例外が発生しなかった場合に実行される else ブロックも追加しています。
  1. 有効な分母でスクリプトを実行します。

    python ~/project/division.py

出力:

Result of division: 5.0
No exception occurred.
Reciprocal: 0.2
  1. 次に、denominator0 に変更して、スクリプトを再度実行します。

    ## division.py
    numerator = 10
    denominator = 0 ## Change the denominator to 0
    success = True
    
    try:
        result = numerator / denominator
        print("Result of division:", result)
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        success = False
    except ValueError:
        print("Error: Invalid input. Please enter a number.")
        success = False
    else:
        print("No exception occurred.")
    
    if success:
        try:
            reciprocal = 1 / result
            print("Reciprocal:", reciprocal)
        except ZeroDivisionError:
            print("Cannot calculate reciprocal of zero.")
    else:
        print("Reciprocal calculation skipped due to error.")

スクリプトを実行します。

python ~/project/division.py

出力:

Error: Cannot divide by zero.
Reciprocal calculation skipped due to error.

これは、except ブロックでフラグを使用してプログラムの流れを制御し、例外が発生したかどうかに基づいて異なるアクションを実行する方法を示しています。

コンテキストマネージャを使った制御

このステップでは、Python のコンテキストマネージャを使って例外処理を簡素化し、例外が発生した場合でもリソースが適切に管理されるようにする方法を学びます。コンテキストマネージャは、ファイル、ネットワーク接続、その他明示的に閉じたり解放したりする必要のあるリソースを扱う際に特に便利です。

コンテキストマネージャは、__enter__ メソッドと __exit__ メソッドを定義するオブジェクトです。with 文は、コンテキストマネージャのコンテキスト内でコードブロックを実行するために使用されます。with ブロックに入るときに __enter__ メソッドが呼び出され、with ブロックを抜けるときには例外が発生したかどうかに関係なく __exit__ メソッドが呼び出されます。

コンテキストマネージャを使ってファイルを読み取る簡単な例から始めましょう。

  1. LabEx 環境で VS Code エディタを開きます。

  2. ~/project ディレクトリに file_handling.py という名前の新しいファイルを作成します。

    touch ~/project/file_handling.py
  3. file_handling.py ファイルを編集し、以下のコードを追加します。

    ## file_handling.py
    
    filename = "my_file.txt"
    
    try:
        with open(filename, "w") as f:
            f.write("Hello, LabEx!\n")
            f.write("This is a test file.\n")
    except IOError as e:
        print(f"An I/O error occurred: {e}")
    
    try:
        with open(filename, "r") as f:
            content = f.read()
            print("File content:")
            print(content)
    except FileNotFoundError:
        print(f"The file '{filename}' was not found.")
    except IOError as e:
        print(f"An I/O error occurred: {e}")

このコードでは、以下のことを行っています。

  • with open(filename, "w") as f: 文を使って、my_file.txt ファイルを書き込みモード ("w") で開きます。open() 関数はファイルオブジェクトを返し、それが変数 f に割り当てられます。
  • with 文は、ブロックを抜けるときに例外が発生した場合でもファイルが自動的に閉じられることを保証します。
  • f.write() メソッドを使って、ファイルに 2 行のテキストを書き込みます。
  • その後、with open(filename, "r") as f: 文を使って、同じファイルを読み取りモード ("r") で開きます。
  • f.read() メソッドを使ってファイルの全内容を読み取り、コンソールに出力します。
  • ファイル操作を try...except ブロックで囲み、潜在的な FileNotFoundErrorIOError 例外を処理します。
  1. スクリプトを実行します。

    python ~/project/file_handling.py

出力:

File content:
Hello, LabEx!
This is a test file.

my_file.txt ファイルが存在しない場合、スクリプトはそれを作成し、指定された内容を書き込みます。ファイルが既に存在する場合、その内容は上書きされます。with 文は、どちらの場合でもファイルが適切に閉じられることを保証します。

ファイル処理の間に例外が発生する可能性のある別の例を考えてみましょう。

## file_handling.py
filename = "my_file.txt"

try:
    with open(filename, "r") as f:
        for line in f:
            ## Simulate an error during processing
            if "test" in line:
                raise ValueError("Simulated error during processing")
            print("Line:", line.strip())
except FileNotFoundError:
    print(f"The file '{filename}' was not found.")
except ValueError as e:
    print(f"A value error occurred: {e}")
except IOError as e:
    print(f"An I/O error occurred: {e}")

この例では、行に "test" という単語が含まれている場合に ValueError を発生させることでエラーをシミュレートしています。このエラーが発生した場合でも、with 文はファイルが適切に閉じられることを保証します。

スクリプトを実行します。

python ~/project/file_handling.py

出力:

Line: Hello, LabEx!
A value error occurred: Simulated error during processing

コンテキストマネージャは、Python でリソースを管理し、例外を処理するクリーンで信頼性の高い方法を提供します。エラーが発生した場合でもリソースが適切に解放されることを保証し、コードをより堅牢で保守しやすくします。

まとめ

この実験では、まず Python の例外処理について学びます。これは堅牢なコードを書くために重要な手法です。最初は、ゼロで割ると ZeroDivisionError が発生し、プログラムが終了する単純な除算の例から始めます。次に、try...except ブロックを実装して ZeroDivisionError を適切に処理し、プログラムがクラッシュするのを防ぎ、代わりに有益なエラーメッセージを表示します。