Pythonスキルの習得

Pythonのエラーハンドリング(例外処理)まとめ – Try〜except 文などを解説 –

Pythonのエラーハンドリング(例外処理)まとめ - Try〜except 文などを解説 -
背景 by AIイラスト

こんにちは、Zero-Cheeseです。

本記事では、Pythonの例外処理について、詳しく解説しています。

コーディング中、しばしば予期しない問題に、直面します。

そんなときに役立つのが、例外処理です。

この記事を読むことで、

  • 例外処理の基本を把握し、
  • より堅牢なコードを書くための手法を習得する

事ができます。

  • Python初心者の方(入門書を読み終わった程度の方)以上を

対象とした、内容となっています。

Pythonのエラーと例外処理

エラーの例外の違い

Pythonにおける「エラー」は、プログラムが期待通りに、動作しない状態を指します。

その中でも、「例外」は特定の状況で発生するエラーで、通常のフローを中断します。

しかし、これらの例外は適切に処理(例外処理)することで、プログラムの完全な停止を防ぐことができます。

より詳細な解説(中・上級者向け)

Pythonの、「エラー(Error)」と「例外(Exception)」は、

  • プログラム実行中の「問題発生時」に、通知するためのメカニズムで、

正確にはすべて「例外」です。

しかし「エラー」という用語は、一般的な会話では、「予期せぬ」または「望ましくない動作」を指すため、本記事でもそのように紹介しております。

よく遭遇する例外の紹介(一部)

Pythonでよく遭遇する例外の一部を、ご紹介します。

  • ZeroDivisionError: 数値を0で割ったときに発生
  • TypeError: 互換性のない型を操作しようとしたときに発生
  • IndexError: 範囲外のインデックスを指定したときに発生

上記は一例ですが、

  • なぜ例外が発生したかを理解し、
  • それに対応するための方法を学ぶことは、

堅牢なプログラム作りには、重要です。

次の章では、Pythonでの例外処理方法について、解説します。

Pythonの例外処理(try-except文)基本

本章では、Pythonで例外を処理するための

  • try-except文の基本的な使い方

について解説します。

try-except文の基本

try-except文の基本的な形式は、次のようになります:

try:
    # 例外が発生する可能性があるコード
except ExceptionType:
    # 例外が発生したときに実行するコード

上記のExceptionTypeは、捕捉したい「例外の種類」を指します。

【具体例】 「ExceptionType」が、「ZeroDivisionError」の場合:

try:
    x = 1 / 0
except ZeroDivisionError:
    print("0で割ることはできません")

このコードでは、0で割るという操作がZeroDivisionErrorを引き起こします。

try文を使用しないと、プログラムが停止します。

try-except文を使用することでこの例外を捕捉し、適切に処理する事ができます。

複数の例外に対する処理の書き方

プログラムによっては、複数の種類の例外が、発生する可能性があります。

この場合、try-except文を使って、複数の例外を個別に処理することができます:

try:
    # 例外が発生する可能性があるコード
except ExceptionType1:
    # ExceptionType1が発生したときに実行するコード
except ExceptionType2:
    # ExceptionType2が発生したときに実行するコード

【具体例】

def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print("0で割ることはできません")
    except TypeError:
        print("数値以外のデータ型で、割り算はできません")

divide(1, 0)  # ZeroDivisionErrorを引き起こします
divide("1", 2)  # TypeErrorを引き起こします

Pythonの例外処理 応用 try-except-else-finally文と例外の送出(raise)

try-except-else-finally文

Pythonのtry-except文は、else句とfinally句を追加することで、拡張することができます。

Pythonコードは以下の通りです。

try:
    # 例外が発生する可能性があるコード
except ExceptionType:
    # 例外が発生したときに実行するコード
else:
    # 例外が発生しなかったときに実行するコード
finally:
    # 例外の有無に関わらず実行するコード
  • else句は、tryブロックで、例外を発生しなかった場合のみ、実行されます。
  • finally句を使用すると、例外の有無に関わらず、特定のコードを実行できます。

このfinally句は、例えばファイルやネットワーク接続のような、リソースをクリーンアップする場合、便利です。

【具体例】

def divide(x, y):
    result = None
    try:
        result = x / y
    except ZeroDivisionError:
        print("0で割ることはできません")
    except TypeError:
        print("数値以外のデータ型で割り算はできません")
    else:
        print(f"結果は {result} です")
    finally:
        if result is None:
            print("結果が得られませんでした")
        else:
            print("計算が完了しました")

divide(1, 0)  
# 「0で割ることはできません  結果が得られませんでした」 (ZeroDivisionErrorが発生)
divide("1", 2)  
# 「数値以外のデータ型で割り算はできません  結果が得られませんでした」 (TypeErrorが発生)
divide(4, 2)  # 「結果は 2.0 です。 計算が完了しました。」

例外の送出(raise)

Pythonではraise文を使って、自分で例外を発生させることができます。

これは、プログラムの実行中に特定のエラー条件を検出した場合や、ユーザーに対して、何らかの問題を明示的に通知したい場合に有用です。

raise ExceptionType("エラーメッセージ")

【具体例】

def validate_age(age):
    if not isinstance(age, int):
        raise TypeError("年齢は整数で指定してください")
    if age < 0:
        raise ValueError("年齢は0以上である必要があります")
    if age > 130:
        raise ValueError("年齢が大きすぎます")

try:
    validate_age("2")
except TypeError as e:
    print(f"エラー: {e}")
    
try:
    validate_age(-1)
except ValueError as e:
    print(f"エラー: {e}")
    
try:
    validate_age(200)
except ValueError as e:
    print(f"エラー: {e}")

Pythonの例外処理 応用2 関数

関数やクラスを設計する際、

  • 不正な値が入力された場合や、
  • 予期せぬエラーが発生した場合に備えて、

例外処理を、適切に組み込みます。

関数が、Noneを返す場合

関数が直接「例外処理」を実行し、プログラムの他の部分に、影響を与えません。

その代わりに、適切なデフォルト値(この場合はNone)が返されます。

この方法は、エラーが致命的でない場合や、その場で処理できる場合に適しています。

【具体例】

def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print("エラー: 0で割ることはできません")
        return None
    return result

関数が、例外を伝搬させる場合

関数が例外を直接処理せずに、呼び出し元に、例外を伝える方法です。

これは、呼び出し元が、

  • 例外を適切に処理する責任がある場合や、
  • 例外が致命的でプログラムの実行を停止するべきである場合に、

適しています。

【具体例】

def divide(x, y):
    if y == 0:
        raise ZeroDivisionError("0で割ることはできません!")
    return x / y

この場合、呼び出し元は適切な例外処理を行うために、try-except文を使用しています。

【呼び出し元のコード】

try:
    result = divide(10, 0)
except ZeroDivisionError as e:
    print(f"エラー: {e}")

Pythonの例外処理 応用3 オブジェクト指向

本章は、オブジェクト指向の知識がある方に向けた内容となっています。

少し、専門的な内容となっています。

オブジェクト指向は便利な一方で、クラス間の関係が複雑になりがちで、その複雑さを管理するのは容易ではありません。

デザインパターンや、様々なアーキテクチャーを駆使して、人間が理解しやすい設計を行いますが、本記事で紹介している例外も、重要な役割を果たします。

オブジェクト指向で使用される例外には、以下のような目的があります。

① 不適切なメソッドの使用を防ぐ

例えば、あるメソッドが特定の状況や条件下でのみ使用すべきである場合、それ以外のでは、例外を発生させるようにします。

下記の例では、openメソッドが、unlockメソッドが呼び出される前に呼び出されると、例外が発生します。

class LockedSafe:
    def __init__(self):
        self._is_locked = True

    def unlock(self):
        self._is_locked = False

    def lock(self):
        self._is_locked = True

    def open(self):
        if self._is_locked:
            raise Exception("Safe is locked. Please unlock before opening.")
        print("Safe is now open.")

# 使用例
safe = LockedSafe()
try:
    safe.open()
except Exception as e:
    print(f"Error: {e}")

② メソッドのパラメータをチェックする

メソッドの引数が、期待された範囲や型でない場合、例外を送出します。

下記の例では、Circleクラスのコンストラクタが、負の数または数値でない引数を受け取ると、例外を送出しています。

class Circle:
    def __init__(self, radius):
        if not isinstance(radius, (int, float)) or radius <= 0:
            raise ValueError("Radius引数が、負の数、もしくはint or float型ではありません。")
        self.radius = radius

# 使用例
try:
    circle = Circle(-5)
except ValueError as e:
    print(f"Error: {e}")

③ クラスの不変性を守る

ある属性が変更されると、クラスの状態が無効になる場合、その変更を防ぐために例外を送出します。

class PositiveInteger:
    def __init__(self, value):
        if not isinstance(value, int) or value <= 0:
            raise ValueError("Value must be a positive integer.")
        self._value = value

# 使用例
num = PositiveInteger(5)
try:
    num.value = -10
except ValueError as e:
    print(f"Error: {e}")

上記クラスのコンストラクタでは、不適切なパラメータが渡された場合、例外が送出されます。

これにより、クラスが無効な状態になるのを、防ぐ事ができます。

まとめと注意点

try-exceptの重要性と役割の再確認

この記事では、

  • try-except文の基本的な使い方から、
  • 複数の例外の処理、
  • さらには自分で例外を作成する方法まで、

さまざまな技術をご紹介しました。

これらの知識を活用すれば、予期せぬエラーが発生したときでも、プログラムを停止させずに、適切なフィードバックを得る事が、可能となります。

(場合によっては、プログラムを停止させるよう、設計できます。)

try-exceptを使う際の注意点

try-except文を活用する際には、特に注意すべき注意点が、2点あります。

1、具体的なエラーのタイプを指定せずに、全ての例外を捕捉するのは避けましょう。

これは、様々なエラーが発生する可能性がある中で、特定のエラーを見逃し、デバッグを困難にする可能性があるからです。

エラータイプを明示的に指定することで、それぞれのエラーに対する適切な対応が可能となります。

2、必要以上にtry-except文を使用することは、避けましょう。

これはコードの可読性を落とすだけでなく、予期せぬエラーを生じる可能性があるからです。

エラーが発生する可能性がある具体的な箇所だけに、「try-except文」を適用するよう、心掛けて下さい。

本記事も、最後までお付き合いいただき、ありがとうございました。

また、お会いしましょう!