読み込み中...

Pythonの例外処理を使ったエラーハンドリングの具体例6選

例外処理 徹底解説 Python
この記事は約32分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●Pythonの例外処理とは?基礎から応用まで

Pythonプログラミングを始めてしばらく経つと、エラーに遭遇する機会が増えてきます。

特にWeb開発やデータ分析の分野で働いているエンジニアの方々は、日々さまざまなエラーと格闘していることでしょう。

エラーが発生したとき、プログラムが突然停止してしまうのは望ましくありません。そこで重要になるのが「例外処理」です。

例外処理は、プログラムの実行中に発生する可能性のあるエラーや異常な状況に対処するための仕組みです。

適切に例外処理を行うことで、プログラムの信頼性と堅牢性が大幅に向上します。

また、デバッグ作業の効率も上がり、より複雑なプロジェクトにも対応できるようになります。

○例外処理の重要性と基本構文

例外処理の重要性は、プログラムの安定性と可読性の向上にあります。

適切に例外をハンドリングすることで、予期せぬエラーが発生しても、プログラムが突然停止することなく、適切に対応できるようになります。

Pythonの例外処理の基本構文は次のようになります。

try:
    # 例外が発生する可能性のあるコード
except ExceptionType:
    # 例外が発生した場合の処理

この構文を使うことで、tryブロック内でエラーが発生した場合に、exceptブロックの処理が実行されます。

ExceptionTypeには、捕捉したい例外の種類を指定します。

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

try-except文の基本的な使い方を理解するために、簡単な例を見てみましょう。

ユーザーから整数を入力してもらい、その値を2で割る処理を考えます。

try:
    num = int(input("整数を入力してください: "))
    result = 10 / num
    print(f"10 ÷ {num} = {result}")
except ValueError:
    print("整数を入力してください。")
except ZeroDivisionError:
    print("0では割り算できません。")

この例では、2つの例外を処理しています。ValueError は、ユーザーが整数以外の値を入力した場合に発生します。

ZeroDivisionErrorは、ユーザーが0を入力した場合に発生します。

○サンプルコード1:シンプルな例外処理

それでは、より実践的なシンプルな例外処理の例を見てみましょう。

ファイルを読み込む処理を例に取ります。

def read_file(filename):
    try:
        with open(filename, 'r') as file:
            content = file.read()
            print(content)
    except FileNotFoundError:
        print(f"ファイル '{filename}' が見つかりません。")
    except IOError:
        print(f"ファイル '{filename}' の読み込み中にエラーが発生しました。")

# 関数の使用例
read_file("example.txt")

この例では、指定されたファイルを読み込もうとします。

ファイルが存在しない場合は FileNotFoundError が、読み込み中に問題が発生した場合は IOError が発生します。

それぞれの例外に対して適切なメッセージを表示することで、ユーザーに何が問題だったのかを明確に伝えることができます。

例外処理を使うことで、プログラムの実行を途中で停止させることなく、エラーに対して適切に対応できるようになります。

また、エラーメッセージを詳細に設定することで、デバッグ作業の効率も向上します。

●6つの具体例で学ぶPythonの例外処理テクニック

Pythonの例外処理の基本を理解したところで、より実践的なテクニックに踏み込んでいきましょう。

Web開発やデータ分析の現場で直面する複雑な状況に対応するため、6つの具体例を通じて高度な例外処理テクニックを詳しく解説していきます。

○サンプルコード2:複数の例外を扱う

実際のプロジェクトでは、一つの処理で複数の例外が発生する可能性があります。

そんな場合、どのように対処すればよいでしょうか。

複数の例外を効率的に扱う方法を見ていきましょう。

def divide_numbers(a, b):
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("ゼロで割ることはできません。")
    except TypeError:
        print("数値を入力してください。")
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")

# 関数の使用例
print(divide_numbers(10, 2))  # 正常な場合
print(divide_numbers(10, 0))  # ゼロ除算
print(divide_numbers("10", 2))  # 型エラー
print(divide_numbers(10, "2"))  # 型エラー

この例では、ZeroDivisionError、TypeError、そしてその他の例外を個別に処理しています。

実行結果は次のようになります。

5.0
ゼロで割ることはできません。
None
数値を入力してください。
None
数値を入力してください。
None

複数の例外を個別に処理することで、エラーの原因をより明確に特定し、適切な対応を取ることができます。

○サンプルコード3:else句とfinally句の活用

try-except文にelse句とfinally句を追加することで、例外処理の柔軟性が大幅に向上します。

else句は例外が発生しなかった場合に実行され、finally句は例外の有無に関わらず必ず実行されます。

def read_and_process_file(filename):
    try:
        with open(filename, 'r') as file:
            content = file.read()
            # ファイルの内容を処理する何らかの操作
            processed_content = content.upper()
    except FileNotFoundError:
        print(f"ファイル '{filename}' が見つかりません。")
        return None
    except IOError:
        print(f"ファイル '{filename}' の読み込み中にエラーが発生しました。")
        return None
    else:
        print("ファイルの読み込みと処理が成功しました。")
        return processed_content
    finally:
        print("ファイル操作の後処理を実行します。")

# 関数の使用例
result = read_and_process_file("example.txt")
if result:
    print(f"処理結果: {result[:50]}...")  # 最初の50文字だけ表示

この例では、ファイルの読み込みと処理を行い、成功した場合にはelse句で成功メッセージを表示し、finally句で後処理を実行しています。

エラーが発生しても、finally句の処理は必ず実行されます。

○サンプルコード4:独自の例外クラスを作成する

プロジェクト固有の例外を扱いたい場合、独自の例外クラスを作成するのが効果的です。

カスタム例外を使うことで、コードの可読性と保守性が向上します。

class InvalidAgeError(Exception):
    def __init__(self, age, message="無効な年齢です。"):
        self.age = age
        self.message = message
        super().__init__(self.message)

def verify_age(age):
    if age < 0 or age > 150:
        raise InvalidAgeError(age, f"{age}は有効な年齢ではありません。0から150の間で入力してください。")
    print(f"年齢 {age} は有効です。")

# 関数の使用例
try:
    verify_age(30)  # 正常な場合
    verify_age(200)  # 無効な年齢
except InvalidAgeError as e:
    print(f"エラー: {e}")

この例では、InvalidAgeErrorという独自の例外クラスを定義しています。

実行結果は次のようになります。

年齢 30 は有効です。
エラー: 200は有効な年齢ではありません。0から150の間で入力してください。

独自の例外クラスを使用することで、エラーメッセージをより具体的かつ意味のあるものにすることができます。

○サンプルコード5:例外の再送出

場合によっては、捕捉した例外を再び送出したいことがあります。

例えば、例外をログに記録した後、上位の呼び出し元に例外を伝播させたい場合などです。

import logging

logging.basicConfig(level=logging.INFO)

def divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        logging.error("ゼロ除算が発生しました")
        raise  # 例外を再送出
    return result

def calculate():
    try:
        result = divide(10, 0)
    except ZeroDivisionError:
        print("計算中にエラーが発生しました")

# 関数の使用例
calculate()

この例では、divide関数でZeroDivisionErrorが発生した場合、ログを記録した後に例外を再送出しています。

実行結果は次のようになります。

ERROR:root:ゼロ除算が発生しました
計算中にエラーが発生しました

例外の再送出を使うことで、エラーの詳細な情報をログに残しつつ、上位の呼び出し元でもエラーを適切に処理することができます。

○サンプルコード6:コンテキストマネージャを使った例外処理

Pythonのwith文を使用したコンテキストマネージャは、リソースの確実な解放を保証する強力な機能です。

ファイル操作やデータベース接続など、リソースの管理が必要な場面で特に有用です。

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name

    def __enter__(self):
        print(f"データベース '{self.db_name}' に接続しています...")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            print(f"エラーが発生しました: {exc_type.__name__} - {exc_value}")
        print(f"データベース '{self.db_name}' との接続を閉じています...")
        return False  # 例外を伝播させる

    def query(self, sql):
        if "ERROR" in sql.upper():
            raise ValueError("不正なSQLクエリです")
        print(f"クエリを実行: {sql}")

# コンテキストマネージャの使用例
try:
    with DatabaseConnection("MyDB") as db:
        db.query("SELECT * FROM users")
        db.query("INSERT ERROR")  # エラーを発生させる
except ValueError as e:
    print(f"ValueError: {e}")

この例では、DatabaseConnectionクラスがコンテキストマネージャとして機能し、データベース接続のオープンとクローズを自動的に処理します。

実行結果は次のようになります。

データベース 'MyDB' に接続しています...
クエリを実行: SELECT * FROM users
エラーが発生しました: ValueError - 不正なSQLクエリです
データベース 'MyDB' との接続を閉じています...
ValueError: 不正なSQLクエリです

コンテキストマネージャを使用することで、リソースの確実な解放が保証され、例外が発生してもリソースがリークすることを防ぐことができます。

○サンプルコード7:非同期処理における例外処理

最後に、非同期プログラミングにおける例外処理について見ていきましょう。

asyncioを使用した非同期処理では、例外処理にも少し異なるアプローチが必要になります。

import asyncio

async def fetch_data(url):
    print(f"{url} からデータを取得中...")
    await asyncio.sleep(2)  # ネットワーク遅延をシミュレート
    if "error" in url:
        raise ConnectionError(f"{url} からのデータ取得に失敗しました")
    return f"{url} からのデータ"

async def main():
    urls = [
        "https://api.example.com/data1",
        "https://api.example.com/error",
        "https://api.example.com/data2"
    ]
    tasks = [fetch_data(url) for url in urls]

    results = []
    for task in asyncio.as_completed(tasks):
        try:
            result = await task
            results.append(result)
        except ConnectionError as e:
            print(f"エラー: {e}")

    print("取得したデータ:")
    for result in results:
        print(result)

# 非同期関数の実行
asyncio.run(main())

この例では、複数のURLからデータを非同期に取得し、エラーが発生した場合でも処理を続行します。

実行結果は次のようになります。

https:// api.example.com/data1 からデータを取得中...
https:// api.example.com/error からデータを取得中...
https:// api.example.com/data2 からデータを取得中...
エラー: https:// api.example.com/error からのデータ取得に失敗しました
取得したデータ:
https:// api.example.com/data1 からのデータ
https:// api.example.com/data2 からのデータ

# リンクの都合上、リンクの箇所に意図的にスペースを入れています

非同期処理における例外処理を適切に行うことで、一部のタスクが失敗しても全体の処理を継続することができ、より堅牢なアプリケーションを構築することができます。

●Pythonの例外処理におけるベストプラクティス

Pythonの例外処理テクニックを学んだ今、より効果的に例外処理を行うためのベストプラクティスについて深掘りしていきましょう。

適切な例外処理は、デバッグ作業の効率を上げ、より複雑なプロジェクトにも対応できるスキルを身につけるための鍵となります。

○適切な粒度で例外をキャッチする

例外処理を行う際、適切な粒度で例外をキャッチすることが重要です。

粒度が粗すぎると特定のエラーに対して適切な対応ができず、細かすぎるとコードが冗長になってしまいます。

適切な粒度を見極めるためには、プログラムの目的と想定されるエラーの種類を十分に理解する必要があります。

例えば、ファイル操作を行う関数を考えてみましょう。

def process_file(filename):
    try:
        with open(filename, 'r') as file:
            content = file.read()
            # ファイルの内容を処理する
            processed_content = content.upper()
            return processed_content
    except FileNotFoundError:
        print(f"ファイル '{filename}' が見つかりません。")
    except PermissionError:
        print(f"ファイル '{filename}' にアクセスする権限がありません。")
    except IOError as e:
        print(f"ファイル '{filename}' の読み込み中にエラーが発生しました: {e}")
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")

# 関数の使用例
result = process_file("example.txt")
if result:
    print("処理結果:", result[:50])  # 最初の50文字だけ表示

この例では、発生する可能性が高い具体的な例外(FileNotFoundError、PermissionError)を個別に処理し、それ以外のIOErrorを一括で処理しています。

さらに、予期せぬエラーに対してもExceptionをキャッチすることで、プログラムの堅牢性を高めています。

○例外の種類に応じた適切な処理

例外をキャッチした後、その種類に応じて適切な処理を行うことが重要です。

単に例外をキャッチしてエラーメッセージを表示するだけでなく、プログラムの状態を適切に回復させたり、代替処理を実行したりすることで、ユーザー体験を向上させることができます。

例えば、ネットワーク接続を行う関数を考えてみましょう。

import time
import random

def connect_to_server(server_url, max_retries=3):
    for attempt in range(max_retries):
        try:
            # サーバーへの接続をシミュレート
            if random.random() < 0.7:  # 70%の確率で接続成功
                print(f"サーバー '{server_url}' に接続しました。")
                return True
            else:
                raise ConnectionError("接続に失敗しました。")
        except ConnectionError as e:
            print(f"試行 {attempt + 1}/{max_retries}: {e}")
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt  # 指数バックオフ
                print(f"{wait_time}秒待機してリトライします...")
                time.sleep(wait_time)

    print(f"サーバー '{server_url}' への接続に {max_retries} 回失敗しました。")
    return False

# 関数の使用例
success = connect_to_server("https://example.com")
if success:
    print("サーバーとの通信を開始します。")
else:
    print("サーバーとの接続を確立できませんでした。後でもう一度お試しください。")

この例では、ConnectionErrorが発生した場合に接続を再試行しています。

さらに、指数バックオフを使用してリトライ間隔を徐々に長くすることで、サーバーへの負荷を軽減しています。

○ログ出力と例外処理の組み合わせ

最後に、ログ出力と例外処理を組み合わせることで、デバッグやトラブルシューティングをより効果的に行うことができます。

Pythonの標準ライブラリに含まれるloggingモジュールを使用すると、簡単にログ出力を実装できます。

import logging

# ログの設定
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def divide_numbers(a, b):
    try:
        result = a / b
        logging.info(f"除算成功: {a} / {b} = {result}")
        return result
    except ZeroDivisionError:
        logging.error(f"ゼロ除算エラー: {a} を 0 で割ろうとしました")
        raise
    except TypeError as e:
        logging.error(f"型エラー: {e}")
        raise

# 関数の使用例
try:
    print(divide_numbers(10, 2))
    print(divide_numbers(10, 0))
except Exception as e:
    print(f"エラーが発生しました: {e}")

try:
    print(divide_numbers("10", 2))
except Exception as e:
    print(f"エラーが発生しました: {e}")

この例では、loggingモジュールを使用して情報ログとエラーログを出力しています。

実行結果は次のようになります。

2024-07-14 12:34:56,789 - INFO - 除算成功: 10 / 2 = 5.0
5.0
2024-07-14 12:34:56,790 - ERROR - ゼロ除算エラー: 10 を 0 で割ろうとしました
エラーが発生しました: division by zero
2024-07-14 12:34:56,791 - ERROR - 型エラー: unsupported operand type(s) for /: 'str' and 'int'
エラーが発生しました: unsupported operand type(s) for /: 'str' and 'int'

ログ出力を活用することで、プログラムの動作をより詳細に追跡し、問題の原因を特定しやすくなります。

また、本番環境でのトラブルシューティングにも役立ちます。

●よくあるエラーと対処法

日々のコーディングで頭を悩ませるエラーに遭遇することも多いのではないでしょうか。

特にWeb開発やデータ分析の分野では、様々なエラーが発生する可能性があります。

ここでは、Pythonでよく遭遇するエラーとその対処法について、具体的な例を交えながら解説していきます。

○NameError:未定義の変数を参照した場合

NameErrorは、定義されていない変数や関数を使用しようとした際に発生するエラーです。

初心者の方がよく遭遇するエラーの一つで、単純なタイプミスが原因であることも多いです。

例えば、次のようなコードを考えてみましょう。

def greet(name):
    message = f"こんにちは、{name}さん!"
    print(mesage)  # タイプミス: 'message' のつもりが 'mesage' になっている

greet("太郎")

このコードを実行すると、次のようなエラーが発生します。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in greet
NameError: name 'mesage' is not defined

このエラーを解決するには、変数名のスペルを正しく修正する必要があります。

修正後のコードは次のようになります。

def greet(name):
    message = f"こんにちは、{name}さん!"
    print(message)  # 'mesage' を 'message' に修正

greet("太郎")

実行結果

こんにちは、太郎さん!

NameErrorに遭遇した場合は、変数名や関数名のスペルミスがないか、また変数が正しく定義されているかを確認しましょう。

○TypeError:不適切な型の操作を行った場合

TypeErrorは、異なる型のオブジェクト間で互換性のない操作を行おうとした際に発生するエラーです。

Pythonは動的型付け言語ですが、型の不一致によるエラーは頻繁に発生します。

例えば、文字列と整数を足し合わせようとした場合を考えてみましょう。

def calculate_age(birth_year):
    current_year = 2024
    age = current_year - birth_year
    return "あなたは" + age + "歳です。"

print(calculate_age(1990))

このコードを実行すると、次のようなエラーが発生します。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in calculate_age
TypeError: can only concatenate str (not "int") to str

このエラーを解決するには、整数を文字列に変換する必要があります。

修正後のコードは次のようになります。

def calculate_age(birth_year):
    current_year = 2024
    age = current_year - birth_year
    return "あなたは" + str(age) + "歳です。"

print(calculate_age(1990))

実行結果

あなたは34歳です。

TypeErrorに遭遇した場合は、操作を行っているオブジェクトの型を確認し、必要に応じて型変換を行いましょう。

○ValueError:不適切な値を使用した場合

ValueErrorは、関数や操作に対して適切でない値を使用した際に発生するエラーです。

例えば、数値を期待する関数に文字列を渡した場合などに発生します。

次のような例を考えてみましょう。ユーザーから入力を受け取り、その値を整数に変換して2倍にする関数があるとします。

def double_number():
    user_input = input("数字を入力してください: ")
    number = int(user_input)
    result = number * 2
    print(f"{number}の2倍は{result}です。")

double_number()

このコードを実行し、ユーザーが数字以外の文字列(例えば “abc”)を入力すると、次のようなエラーが発生します。

数字を入力してください: abc
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in double_number
ValueError: invalid literal for int() with base 10: 'abc'

このエラーを防ぐには、try-except文を使用してValueErrorをキャッチし、適切なエラーメッセージを表示するように修正します。

def double_number():
    while True:
        try:
            user_input = input("数字を入力してください: ")
            number = int(user_input)
            result = number * 2
            print(f"{number}の2倍は{result}です。")
            break
        except ValueError:
            print("無効な入力です。数字を入力してください。")

double_number()

この修正により、ユーザーが無効な入力を行った場合でもプログラムがクラッシュすることなく、適切なエラーメッセージを表示して再入力を促すことができます。

実行結果

数字を入力してください: abc
無効な入力です。数字を入力してください。
数字を入力してください: 5
5の2倍は10です。

ValueErrorに遭遇した場合は、入力値の検証を行うか、try-except文を使用してエラーを適切に処理することが重要です。

●Pythonの例外処理の応用例

Pythonの例外処理の基本と実践的なテクニックを学んできましたが、実際のプロジェクトではどのように活用されているのでしょうか。

皆さんにとって、具体的な応用例を見ることは非常に重要です。

ここでは、Web開発やデータ分析の現場でよく遭遇する場面での例外処理の応用例を紹介します。

○ファイル操作における例外処理

ファイル操作は多くのプログラムで必要不可欠な処理ですが、同時に様々なエラーが発生する可能性もあります。

ファイルが存在しない、アクセス権限がない、ディスク容量が不足しているなど、様々な状況に対応する必要があります。

ファイルの読み書きを行う関数の例を見てみましょう。

import os

def read_and_write_file(input_file, output_file):
    try:
        # 入力ファイルを読み込む
        with open(input_file, 'r') as file:
            content = file.read()

        # 内容を加工する(ここでは単純に大文字に変換)
        processed_content = content.upper()

        # 出力ファイルに書き込む
        with open(output_file, 'w') as file:
            file.write(processed_content)

        print(f"ファイルの処理が完了しました。結果は {output_file} に保存されています。")

    except FileNotFoundError:
        print(f"エラー: ファイル '{input_file}' が見つかりません。")
    except PermissionError:
        print(f"エラー: ファイル '{input_file}' または '{output_file}' にアクセスする権限がありません。")
    except IOError as e:
        print(f"エラー: ファイル操作中に問題が発生しました: {e}")
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")
    finally:
        print("ファイル操作を終了します。")

# 関数の使用例
read_and_write_file("input.txt", "output.txt")

この関数は、入力ファイルの内容を読み込み、大文字に変換して出力ファイルに書き込みます。

例外処理を使用することで、様々なエラー状況に適切に対応しています。

実行結果(正常な場合)

ファイルの処理が完了しました。結果は output.txt に保存されています。
ファイル操作を終了します。

実行結果(入力ファイルが存在しない場合)

エラー: ファイル 'input.txt' が見つかりません。
ファイル操作を終了します。

○ネットワーク通信における例外処理

Web開発やデータ分析の分野では、ネットワーク通信を扱うことが多くあります。

API呼び出しやウェブスクレイピングなどの処理では、ネットワークの状態やサーバーの応答に応じて適切に例外処理を行う必要があります。

ここでは、Web APIからデータを取得する関数の例を紹介します。

import requests
import time

def fetch_data_from_api(url, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()  # HTTPエラーがあれば例外を発生させる
            return response.json()

        except requests.exceptions.HTTPError as e:
            print(f"HTTPエラー: {e}")
            if response.status_code == 429:  # レートリミット
                print("レートリミットに達しました。しばらく待機します。")
                time.sleep(60)  # 1分待機
            else:
                print(f"リトライ {attempt + 1}/{max_retries}")

        except requests.exceptions.ConnectionError:
            print("接続エラー: サーバーに接続できません。")

        except requests.exceptions.Timeout:
            print("タイムアウト: サーバーからの応答がありません。")

        except requests.exceptions.RequestException as e:
            print(f"リクエスト中にエラーが発生しました: {e}")

        if attempt < max_retries - 1:
            wait_time = 2 ** attempt  # 指数バックオフ
            print(f"{wait_time}秒待機してリトライします...")
            time.sleep(wait_time)

    print(f"{max_retries}回のリトライ後も失敗しました。")
    return None

# 関数の使用例
api_url = "https://api.example.com/data"
data = fetch_data_from_api(api_url)
if data:
    print("取得したデータ:", data)
else:
    print("データの取得に失敗しました。")

この関数は、指定されたURLからデータを取得し、様々なネットワークエラーに対処します。

レートリミットやタイムアウトなどの一時的な問題に対しては、リトライロジックを実装しています。

実行結果(正常な場合)

取得したデータ: {'key': 'value', ...}

実行結果(接続エラーの場合)

接続エラー: サーバーに接続できません。
2秒待機してリトライします...
接続エラー: サーバーに接続できません。
4秒待機してリトライします...
接続エラー: サーバーに接続できません。
3回のリトライ後も失敗しました。
データの取得に失敗しました。

○データベース操作における例外処理

データベース操作は多くのアプリケーションで中心的な役割を果たしますが、同時に様々なエラーが発生する可能性があります。

接続エラー、クエリエラー、トランザクションエラーなど、データベース特有の問題に適切に対処する必要があります。

ここでは、SQLiteデータベースを使用してデータを挿入する関数の例を見ていきましょう。

import sqlite3

def insert_user_data(db_file, user_id, name, email):
    connection = None
    try:
        connection = sqlite3.connect(db_file)
        cursor = connection.cursor()

        # ユーザーデータを挿入するSQLクエリ
        insert_query = """
        INSERT INTO users (user_id, name, email)
        VALUES (?, ?, ?)
        """
        cursor.execute(insert_query, (user_id, name, email))

        connection.commit()
        print(f"ユーザー '{name}' のデータを正常に挿入しました。")

    except sqlite3.IntegrityError:
        print(f"エラー: ユーザーID '{user_id}' は既に存在します。")
        connection.rollback()

    except sqlite3.OperationalError as e:
        print(f"データベース操作エラー: {e}")
        connection.rollback()

    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")
        if connection:
            connection.rollback()

    finally:
        if connection:
            connection.close()
            print("データベース接続を閉じました。")

# 関数の使用例
db_file = "users.db"
insert_user_data(db_file, 1, "山田太郎", "yamada@example.com")
insert_user_data(db_file, 1, "鈴木花子", "suzuki@example.com")  # 重複エラーを発生させる

この関数は、ユーザーデータをデータベースに挿入し、様々なデータベース関連のエラーに対処します。

トランザクションを使用することで、エラーが発生した場合にデータの一貫性を保つことができます。

実行結果

ユーザー '山田太郎' のデータを正常に挿入しました。
データベース接続を閉じました。
エラー: ユーザーID '1' は既に存在します。
データベース接続を閉じました。

まとめ

Pythonの例外処理について、基礎から応用まで幅広く解説してきました。

今回学んだ内容を実際のコードに適用し、練習を重ねることで、例外処理のスキルは確実に向上していきます。

始めは少し難しく感じるかもしれませんが、徐々に自然に適切な例外処理を実装できるようになるはずです。