【Python】例外をスロー(raise)してエラーを管理する方法を初心者向けに解説

はじめに

Pythonでプログラムを書いていると、ファイルの読み込み失敗や数値の誤入力など、予期せぬエラーが起こる場合があります。
こうしたエラーを例外と呼び、適切に処理しないとプログラムが途中で止まってしまうことがあるでしょう。

とはいえ、初心者の皆さんにとって、何が「例外」で何が「エラー処理」なのか、そしてそれをどう使いこなせばよいのかは少しわかりにくいかもしれません。
この記事では、Python 例外 スローの具体的な仕組みや使い方を丁寧に解説します。

この記事を読むとわかること

  • 例外とは何かと、その役割
  • try-except 構文の基本的な使い方
  • raise による例外のスロー方法
  • 実務でよくある例外処理のシーン
  • カスタム例外の定義と活用方法

例外とは何か

例外とは、プログラムの実行中に起きる想定外の状況を示す仕組みのことです。
たとえば次のような状況が挙げられます。

  • 存在しないファイルを開こうとした
  • 文字列を数値に変換しようとしたところ、変換できない文字列だった
  • 通信先のサーバーが応答しなかった
  • ユーザーが不正な入力をした

通常の手続き通りに処理を進めるとエラーが起きるようなケースで、何もしないとプログラムが止まってしまうことがあります。
しかし、例外を適切に処理すると「ファイルが存在しない場合にファイルを作成する」「不正な入力があったら再入力を促す」といった柔軟な対応が可能になります。

例外処理が必要となる理由

エラー自体を無視してプログラムを継続しようとすると、データの破損や誤動作が起こり得ます。
逆に、エラーが起こるたびに強制終了してしまうのも使いづらいはずです。
そこでPythonは、例外をスローして、受け取った側がエラー処理を行うという仕組みを用意しています。
これによって、予測不能な事態にも柔軟に対処できるようになります。

Pythonにおける例外の基本構文

Pythonでは、 **例外を起こす(スローする) ときに raise **キーワードを使い、起きた例外をキャッチ (受け取る)ときに try-except ブロックを使います。 スローは「投げる」、キャッチは「受け取る」というイメージで考えるとわかりやすいかもしれません。

try-except構文の流れ

例外処理は次のような流れで行われます。

  1. try ブロックで特定の処理を実行する
  2. 処理の中で例外が起こる(または明示的に raise される)
  3. except ブロックが呼び出され、例外を処理する

具体的には以下のように書きます。

try:
    # ここで何らかの処理を実行
    # 例: ファイルを開く、数値計算をするなど
except SomeError:
    # 例外が発生したときの処理

一度でもプログラムを書いたことがある方なら、if-else 文のエラー版のようなイメージかもしれません。
しかし、実行途中で起こる異常を処理するための専用機能だという点が大きな違いです。

複数のexceptを使う

Pythonでは1つの try ブロックに対して複数の except を設定することができます。
たとえば、ファイル読み込みで起こり得るいくつかのエラーに応じて処理を分けられます。

try:
    with open("example.txt", "r") as f:
        content = f.read()
    number = int(content)
except FileNotFoundError:
    print("ファイルが見つかりませんでした。")
except ValueError:
    print("ファイルの中身を数値に変換できませんでした。")

上記の例では、FileNotFoundError が起きた場合と ValueError が起きた場合の処理を分けています。
実務でも、同じ操作で想定されるエラーを複数キャッチする場面はよくあります。

Python 例外 スロー:raiseを使った例外の発生

では、 明示的に例外をスロー (発生) させたいときはどうするのでしょうか。 Pythonでは raise キーワードを使います。

def calculate_discount(price, discount_rate):
    if discount_rate < 0 or discount_rate > 1:
        raise ValueError("割引率は0以上1以下で指定してください。")
    return price * (1.0 - discount_rate)

try:
    result = calculate_discount(1000, 1.2)
    print("割引後の価格:", result)
except ValueError as e:
    print("エラー:", e)

ここで calculate_discount 関数の中で raise ValueError(...) を呼び出し、値が不正だった場合に例外をスローしています。
呼び出し元では try-except を使って受け取り、エラーメッセージを表示しています。

このように自分で意図的に例外をスローできることで、エラー状態をはっきり示せるだけでなく、呼び出し元に柔軟な対処を委ねることができるのです。

実務での活用シーン

現場でPythonを使うときは、ファイルの取り扱い、外部サービスとの通信、ユーザー入力など、エラーが発生しやすいポイントが多々あります。
ここでは、業務システムなどでよくある場面を想定してみます。

1. Webアプリの入力フォーム

ユーザーが数値を入力するフォームがあったとします。
たとえば、商品個数にマイナスの値を入力する方はいないと思いますが、誤って変な文字列が入力されることは少なくありません。
このとき、入力された値が不正な場合はサーバー側の処理で例外スローを行い、フロントエンドにメッセージを返すことで、ユーザーに再入力を促すことが可能です。

2. ファイルの読み書き

業務で扱うCSVファイルが壊れている、あるいはそもそもファイルが存在しないといったケースが考えられます。
こうしたとき、ファイルを開く際に起こりうる例外をキャッチして、ユーザーに「ファイルが見当たりません」と知らせたり、別のフォルダを探しにいったりするわけです。

3. 外部サービスへのAPIリクエスト

外部サービスとの連携では、サーバーがダウンしていたり、通信障害が起きたりするかもしれません。
その場合、レスポンスが返ってこない、またはエラーコードが返ってくるといった状況になります。
これもPythonの例外処理でハンドリングし、「もう一度試す」「別のサービスを使う」などの対応が可能です。

エラーが起きそうな箇所を事前に洗い出し、想定される例外をしっかりキャッチ&スローすることが大切です。

try-except-finally構文

もう1つ便利な構文として、finally があります。
finally ブロックに書かれた処理は、例外が発生してもしなくても必ず最後に実行される特徴があります。

try:
    f = open("data.txt", "r")
    data = f.read()
except FileNotFoundError:
    print("ファイルが見つかりません。")
finally:
    if 'f' in locals() and not f.closed:
        f.close()

ここでは、例外が発生した場合でも、finally ブロックでファイルを閉じる処理を行っています。
実務では、ネットワーク接続やデータベース接続を開いた後に必ずクローズしたいときなどに活用できます。

カスタム例外の作り方

標準ライブラリに用意された例外クラスだけでは足りない場面もあります。
そんなときはカスタム例外を定義します。

class CustomError(Exception):
    pass

def sample_process(value):
    if value < 0:
        raise CustomError("負の数は処理できません。")
    return value * 2

try:
    result = sample_process(-1)
    print("結果:", result)
except CustomError as e:
    print("カスタム例外を受け取りました:", e)

上記のように Exception を継承して独自クラスを作成し、自由にカスタマイズできるのがPythonの便利な点です。
業務アプリのコード規模が大きくなると、オリジナルの例外クラスを整備して可読性を高めることが多々あります。

カスタム例外を使うメリット

  • エラーの種類を明確化できる(自分のアプリに固有のエラーを示す)
  • 複雑なアプリケーションで使うときに保守性が高まる
  • except CustomError のように、任意の例外だけをキャッチできる

適切にクラス名を付けることで、エラーの原因をすぐ把握できるようになるのもメリットです。

例外処理のベストプラクティス

例外処理を正しく使うためには、いくつかのベストプラクティスがあります。
以下のポイントを意識すると、コードが読みやすくメンテナンスしやすくなります。

1. 必要最小限の例外をキャッチする

初心者がよくやりがちな失敗として、except Exception: ですべての例外を一括で捕まえてしまうというパターンがあります。
一見するとエラーを一気に処理できて便利そうですが、プログラム上で本当にケアすべきエラーを見逃すことにもつながりかねません。
想定している例外だけをキャッチするか、あるいはログを取るだけに留めるなど、適度に絞ることが大切です。

2. 例外メッセージで原因をわかりやすく伝える

raise するときには、何が問題だったのかを端的に示すメッセージをつけましょう。
たとえば「価格がマイナスです」「ファイル名が空です」など、エラーが起きた理由を明示すると、エラーを受け取った側は次の行動を取りやすくなります。

3. 深いネストは避ける

try-except ブロックの中でさらに try-except が入ると、コードのネストが深くなりがちです。
読み手に負担をかけるため、なるべく細かい関数に分けたり、処理をまとめたりして整理しましょう。
見通しのよいコードはエラー原因の追及や修正もしやすくなります。

エラーをただ無視することはおすすめできません。
後々深刻な不具合に発展する可能性があるため、何らかの処理を行うのが望ましいでしょう。

具体例:数値変換と再入力プロンプト

ここで少しだけ具体的なコード例をもう一つ紹介します。
数値を受け取る処理で、再入力を求める流れを作ってみましょう。

def input_number():
    while True:
        user_input = input("数値を入力してください:")
        try:
            number = float(user_input)
            return number
        except ValueError:
            print("数値に変換できませんでした。もう一度入力してください。")

def main():
    num = input_number()
    print("入力された数値:", num)

if __name__ == "__main__":
    main()
  • input_number() でユーザーが正しい数値を入力するまでループ
  • 変換できない文字列が入力されれば ValueError がスローされるので、再度入力を促す

こうしたリトライが必要な場面は実務でも多々あります。
ネットワーク通信やファイルの読み込みなど、状況次第ではもう一度試したいケースは多いものです。
例外処理をうまく利用することで、プログラムの流れを柔軟にコントロールできます。

まとめ

Pythonでの例外スローは、エラーが起きてもプログラムを柔軟に継続し、状況に応じた対処を行うための基本機能です。
try-except 構文や raise、カスタム例外などを組み合わせることで、思わぬエラーをうまく切り分けて扱えます。

初心者の皆さんはまず、ファイル操作やユーザー入力などエラーが発生しやすい箇所から例外処理を練習してみてください。
コードの可読性も高まり、バグ発生時の原因追求が容易になるはずです。

エラーが起きたときにすぐにプログラムが止まってしまうのではなく、エラーの内容を分かりやすく伝えたり、別の処理に切り替えたりする。
こうした工夫こそが例外をスローする大きな目的と言えるでしょう。

今後、プログラム規模が大きくなる場合や、チーム開発を行う際には、例外処理が正しく設計されているかどうかが品質を大きく左右します。
ここで紹介した内容を参考にして、Pythonの例外スローを活用してください。

Pythonをマスターしよう

この記事で学んだPythonの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。