Python例外処理の基本|try-exceptでエラーに対処
Python例外処理の基本的な使い方を初心者向けに解説。try-except文の書き方、各種例外の種類、finally文、カスタム例外まで、実例とともに詳しく紹介します。
Python例外処理の基本|try-exceptでエラーに対処
みなさん、プログラムを実行中にエラーで止まってしまった経験ありませんか?
「プログラムがエラーで止まらないようにしたい」 「try-except文って聞いたことあるけど、どう使うの?」 「エラーが出ても続けて実行させたい」
こんな悩み、よくありますよね。
実は、Pythonには例外処理という便利な仕組みがあります。 これを使えば、エラーが起きてもプログラムを止めずに、適切に対処できるようになるんです。
この記事では、Python の例外処理の基本から、try-except文の使い方、実践的なエラー対処法まで、初心者にも分かりやすく解説します。 例外処理をマスターして、エラーに強い安定したプログラムを作れるようになりましょう!
例外処理って何?
例外処理は、プログラム実行中に発生するエラーに対処するための仕組みです。
簡単に言うと、「エラーが起きた時の対処法を事前に決めておく」ということです。
プログラムエラーの種類
プログラムで発生するエラーには、大きく2つの種類があります。
構文エラー(プログラムが実行される前に発見される)
# 構文エラーの例# if True # SyntaxError: コロンが抜けている
これは、プログラムを書く時の文法ミスです。 Pythonが「これは間違った書き方だよ」と教えてくれます。
実行時エラー(プログラム実行中に発生する)
# 実行時エラーの例number = int("abc") # ValueError: 文字列を数値に変換できない
これは、プログラムを実行している時に起きるエラーです。 文法は正しいけど、実際に動かすと問題が起きるパターンですね。
例外処理は、この「実行時エラー」に対処するための仕組みです。
例外処理が重要な理由
なぜ例外処理が大切なのか、例を見てみましょう。
例外処理なしの場合
def divide_without_handling(a, b): return a / b
# ゼロで割ろうとするとプログラムが止まってしまうresult = divide_without_handling(10, 0) # ZeroDivisionErrorprint("この行は実行されません")
エラーが起きると、プログラムがそこで止まってしまいます。
例外処理ありの場合
def divide_with_handling(a, b): try: return a / b except ZeroDivisionError: print("ゼロで割ることはできません") return None
result = divide_with_handling(10, 0)print(f"結果: {result}")print("プログラムは続きます")
実行すると、こんな感じになります。
ゼロで割ることはできません
結果: None
プログラムは続きます
例外処理を使うと、エラーが発生してもプログラムを継続できます。 とても便利ですよね!
例外処理の基本要素
Pythonの例外処理には、以下の要素があります。
try文
- エラーが発生する可能性のあるコードを記述
- 「このコードは危険かも」という部分
except文
- 特定の例外が発生した時の処理を記述
- 「こんなエラーが起きたらこうしよう」という部分
else文
- 例外が発生しなかった時の処理を記述
- 「エラーが起きなかった時はこれをやろう」という部分
finally文
- 例外の有無に関わらず必ず実行される処理
- 「何があっても最後にこれはやろう」という部分
例えば、ファイル操作では、ファイルが存在しない場合の対処がとても重要になります。
try-except文の基本
それでは、try-except文の基本的な使い方を見てみましょう。
基本的な書き方
try-except文の基本的な構文はこちらです。
try: # エラーが発生する可能性のあるコード number = int(input("数字を入力してください: ")) result = 100 / number print(f"結果: {result}")except ValueError: # 数値変換エラーの処理 print("正しい数字を入力してください")except ZeroDivisionError: # ゼロ除算エラーの処理 print("ゼロで割ることはできません")
このように書くと、異なる種類のエラーに対してそれぞれ異なる対処ができます。
例えば、ユーザーが「abc」と入力するとValueError
が起き、「0」と入力するとZeroDivisionError
が起きます。
どちらのエラーにも対応できるので安心ですね。
全ての例外をキャッチ
すべての例外をまとめてキャッチすることもできます。
try: # 何らかの処理 data = {"name": "田中", "age": 25} print(data["height"]) # KeyErrorexcept Exception as e: print(f"エラーが発生しました: {e}") print(f"エラーの種類: {type(e).__name__}")
実行すると、こんな感じになります。
エラーが発生しました: 'height'
エラーの種類: KeyError
Exception
は、ほとんどの例外の基底クラスです。
つまり、ほぼ全てのエラーをキャッチできるんです。
例外オブジェクトの活用
例外オブジェクトから詳細情報を取得できます。
try: number = int("abc")except ValueError as e: print(f"エラーメッセージ: {e}") print(f"エラーの種類: {type(e).__name__}") print(f"エラーの引数: {e.args}")
実行すると、こうなります。
エラーメッセージ: invalid literal for int() with base 10: 'abc'
エラーの種類: ValueError
エラーの引数: ("invalid literal for int() with base 10: 'abc'",)
例外オブジェクトから、エラーの詳細情報を取得できて便利ですね。
複数の例外を同時にキャッチ
複数の例外を同時にキャッチすることもできます。
try: # ファイル操作 with open("存在しないファイル.txt") as f: content = f.read()except (FileNotFoundError, PermissionError) as e: print(f"ファイル操作エラー: {e}") print(f"エラーの種類: {type(e).__name__}")
このように書くと、複数の種類のエラーを同じ方法で処理できます。
主要な例外の種類
プログラミングでよく発生する例外を覚えておきましょう。
よく発生する例外
基本的な例外の種類と対処法を見てみます。
ValueError - 値が不適切
try: number = int("abc")except ValueError: print("文字列を数値に変換できません")
数値に変換できない文字列を変換しようとした時に起きます。
TypeError - 型が不適切
try: result = "文字列" + 123except TypeError: print("文字列と数値は結合できません")
異なる型同士で演算しようとした時に起きます。
IndexError - インデックスが範囲外
try: my_list = [1, 2, 3] print(my_list[5])except IndexError: print("リストの範囲外です")
リストの存在しない場所にアクセスしようとした時に起きます。
KeyError - 辞書のキーが存在しない
try: my_dict = {"name": "田中", "age": 25} print(my_dict["height"])except KeyError: print("指定されたキーは存在しません")
辞書に存在しないキーにアクセスしようとした時に起きます。
AttributeError - 属性が存在しない
try: my_string = "Hello" my_string.append("World")except AttributeError: print("文字列にappendメソッドはありません")
オブジェクトに存在しないメソッドや属性にアクセスしようとした時に起きます。
これらの例外を理解することで、適切な対処ができるようになります。
ファイル操作関連の例外
ファイル操作でよく発生する例外も覚えておきましょう。
FileNotFoundError - ファイルが見つからない
try: with open("存在しないファイル.txt", "r") as f: content = f.read()except FileNotFoundError: print("ファイルが見つかりません")
指定したファイルが存在しない時に起きます。
PermissionError - アクセス権限がない
try: with open("/etc/passwd", "w") as f: f.write("データ")except PermissionError: print("ファイルの書き込み権限がありません")
ファイルやディレクトリにアクセスする権限がない時に起きます。
IsADirectoryError - ディレクトリをファイルとして開こうとした
try: with open("/", "r") as f: content = f.read()except IsADirectoryError: print("ディレクトリをファイルとして開くことはできません")
ディレクトリをファイルのように扱おうとした時に起きます。
ファイル操作では、これらの例外への対処がとても重要ですね。
ネットワーク関連の例外
ネットワーク操作での例外例も見てみましょう。
import urllib.requestimport urllib.error
def fetch_url(url): try: with urllib.request.urlopen(url) as response: return response.read().decode('utf-8') except urllib.error.URLError as e: print(f"URLエラー: {e}") return None except urllib.error.HTTPError as e: print(f"HTTPエラー: {e.code} - {e.reason}") return None except Exception as e: print(f"予期しないエラー: {e}") return None
# 使用例content = fetch_url("https://example.com")if content: print("データを取得しました")else: print("データの取得に失敗しました")
ネットワーク処理では、接続エラーやHTTPエラーへの対処が必要です。 インターネットの接続状況によってエラーが起きやすいので、しっかりと例外処理をしておきましょう。
else文とfinally文
try-except文には、else文とfinally文も追加できます。
else文の使用
else文は、例外が発生しなかった場合の処理を記述します。
def safe_divide(a, b): try: result = a / b except ZeroDivisionError: print("ゼロで割ることはできません") return None else: # 例外が発生しなかった場合の処理 print(f"計算が正常に完了しました") return result finally: # 必ず実行される処理 print("計算処理を終了します")
# 使用例print("=== 正常ケース ===")result1 = safe_divide(10, 2)print(f"結果: {result1}")
print("=== エラーケース ===")result2 = safe_divide(10, 0)print(f"結果: {result2}")
実行すると、こんな感じになります。
=== 正常ケース ===
計算が正常に完了しました
計算処理を終了します
結果: 5.0
=== エラーケース ===
ゼロで割ることはできません
計算処理を終了します
結果: None
else文は、try文が正常に実行された場合にのみ実行されます。 成功した時だけ行いたい処理がある場合に便利ですね。
finally文の使用
finally文は、例外の有無に関わらず必ず実行されます。
def read_file_with_cleanup(filename): file_handle = None try: print(f"ファイル {filename} を開いています...") file_handle = open(filename, 'r') content = file_handle.read() return content except FileNotFoundError: print("ファイルが見つかりません") return None except Exception as e: print(f"予期しないエラー: {e}") return None finally: # リソースのクリーンアップ if file_handle: print("ファイルを閉じています...") file_handle.close() print("処理を完了しました")
# 使用例content = read_file_with_cleanup("test.txt")
実行すると、ファイルが存在しない場合でも、finally文の内容が実行されます。
ファイル test.txt を開いています...
ファイルが見つかりません
処理を完了しました
finally文は、リソースのクリーンアップでよく使用されます。 ファイルを開いたら確実に閉じる、データベースに接続したら確実に切断する、といった場面で役立ちます。
with文による自動リソース管理
Pythonでは、with文を使ってより安全にリソース管理ができます。
def read_file_safely(filename): try: # with文により、自動的にファイルがクローズされる with open(filename, 'r', encoding='utf-8') as f: content = f.read() return content except FileNotFoundError: print("ファイルが見つかりません") return None except UnicodeDecodeError: print("文字エンコーディングエラーです") return None except Exception as e: print(f"予期しないエラー: {e}") return None
# 使用例content = read_file_safely("sample.txt")if content: print(f"ファイル内容: {content[:100]}...")
with文を使うことで、finally文を書かなくてもリソースが適切に管理されます。 ファイル操作では、with文を使うのが推奨されています。
カスタム例外
独自の例外クラスを作成することもできます。
独自の例外クラス
プログラムの目的に応じて、独自の例外を定義できます。
class CustomError(Exception): """カスタム例外クラス""" pass
class ValidationError(Exception): """バリデーションエラー""" def __init__(self, message, field_name=None): super().__init__(message) self.field_name = field_name
class BusinessLogicError(Exception): """ビジネスロジックエラー""" def __init__(self, message, error_code=None): super().__init__(message) self.error_code = error_code
# 使用例def validate_age(age): if not isinstance(age, int): raise ValidationError("年齢は整数である必要があります", "age") if age < 0: raise ValidationError("年齢は0以上である必要があります", "age") if age > 150: raise ValidationError("年齢は150以下である必要があります", "age")
try: validate_age(-5)except ValidationError as e: print(f"バリデーションエラー: {e}") print(f"フィールド: {e.field_name}")
実行すると、こうなります。
バリデーションエラー: 年齢は0以上である必要があります
フィールド: age
カスタム例外により、具体的なエラー情報を提供できます。 プログラムの用途に応じて、分かりやすいエラーメッセージを設計できるのは便利ですね。
例外の再発生
例外をキャッチした後、再度発生させることもできます。
def process_data_with_logging(data): try: # データ処理 if not data: raise ValueError("データが空です") result = [] for item in data: if not isinstance(item, (int, float)): raise TypeError(f"数値以外のデータがあります: {item}") result.append(item * 2) return result except Exception as e: # エラーをログに記録 print(f"エラーログ: {type(e).__name__} - {e}") # 例外を再発生させる raise
# 使用例try: result = process_data_with_logging([1, 2, "abc", 4])except Exception as e: print(f"最終的なエラー処理: {e}")
実行すると、こうなります。
エラーログ: TypeError - 数値以外のデータがあります: abc
最終的なエラー処理: 数値以外のデータがあります: abc
raise
文により、例外を上位の呼び出し元に伝播できます。
ログを記録してから、エラーを上位に伝えたい場合などに便利です。
実践的な例外処理
それでは、実際の開発でよく使われる例外処理の例を見てみましょう。
ユーザー入力の検証
ユーザー入力を安全に処理する例をご紹介します。
def get_user_input(): """安全なユーザー入力取得""" while True: try: age = input("年齢を入力してください: ") age = int(age) if age < 0: print("年齢は0以上で入力してください") continue if age > 150: print("年齢は150以下で入力してください") continue return age except ValueError: print("数字を入力してください") except KeyboardInterrupt: print("入力がキャンセルされました") return None
# 使用例(デモ用に入力をシミュレート)def demo_user_input(): print("=== ユーザー入力デモ ===") print("正常な入力: 25") age = 25 # 実際は get_user_input() を使用 if age is not None: print(f"入力された年齢: {age}歳") print("無効な入力処理のデモ:") print("- 文字列入力の場合: ValueError をキャッチ") print("- 負の数の場合: 再入力を求める") print("- 大きすぎる数の場合: 再入力を求める")
demo_user_input()
このように書くと、ユーザーが間違った入力をしても、プログラムが止まらずに再入力を求められます。
ファイル処理システム
堅牢なファイル処理システムの例です。
import osimport jsonfrom datetime import datetime
class FileProcessor: def __init__(self, log_file="error_log.txt"): self.log_file = log_file def log_error(self, error_message): """エラーログを記録""" try: timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with open(self.log_file, "a", encoding="utf-8") as f: f.write(f"[{timestamp}] {error_message}") except Exception: print("ログの記録に失敗しました") def read_json_file(self, filename): """JSONファイルを安全に読み込み""" try: if not os.path.exists(filename): raise FileNotFoundError(f"ファイルが見つかりません: {filename}") with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) print(f"ファイル {filename} を正常に読み込みました") return data except FileNotFoundError as e: error_msg = f"ファイルエラー: {e}" print(error_msg) self.log_error(error_msg) return None except json.JSONDecodeError as e: error_msg = f"JSON形式エラー in {filename}: {e}" print(error_msg) self.log_error(error_msg) return None except PermissionError as e: error_msg = f"ファイルアクセス権限エラー: {e}" print(error_msg) self.log_error(error_msg) return None except Exception as e: error_msg = f"予期しないエラー in {filename}: {e}" print(error_msg) self.log_error(error_msg) return None def write_json_file(self, filename, data): """JSONファイルを安全に書き込み""" try: # バックアップファイルを作成 if os.path.exists(filename): backup_name = f"{filename}.backup" os.rename(filename, backup_name) print(f"バックアップを作成しました: {backup_name}") with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"ファイル {filename} に正常に書き込みました") return True except Exception as e: error_msg = f"ファイル書き込みエラー in {filename}: {e}" print(error_msg) self.log_error(error_msg) return False
# 使用例processor = FileProcessor()
# テストデータtest_data = { "users": [ {"name": "田中", "age": 25, "city": "東京"}, {"name": "佐藤", "age": 30, "city": "大阪"} ], "timestamp": datetime.now().isoformat()}
print("=== ファイル処理システムのデモ ===")
# ファイル書き込みテストif processor.write_json_file("users.json", test_data): # ファイル読み込みテスト loaded_data = processor.read_json_file("users.json") if loaded_data: print(f"読み込んだデータ: {loaded_data}")
# 存在しないファイルの読み込みテストprint("=== エラーケースのテスト ===")processor.read_json_file("nonexistent.json")
このシステムでは、様々なエラーに対して適切な処理を行い、ログも記録します。 実際の業務でも使えるような、堅牢な作りになっています。
Web APIクライアント
例外処理を活用したWeb APIクライアントの例です。
import urllib.requestimport urllib.errorimport jsonimport time
class APIClient: def __init__(self, base_url, max_retries=3): self.base_url = base_url self.max_retries = max_retries def make_request(self, endpoint, method="GET", data=None): """APIリクエストを送信""" url = f"{self.base_url}/{endpoint}" for attempt in range(self.max_retries): try: if method == "GET": response = self._get_request(url) elif method == "POST": response = self._post_request(url, data) else: raise ValueError(f"サポートされていないメソッド: {method}") return response except urllib.error.HTTPError as e: if e.code in [500, 502, 503, 504] and attempt < self.max_retries - 1: print(f"サーバーエラー({e.code})のため再試行します... ({attempt + 1}/{self.max_retries})") time.sleep(2 ** attempt) # 指数バックオフ continue else: print(f"HTTPエラー: {e.code} - {e.reason}") return None except urllib.error.URLError as e: if attempt < self.max_retries - 1: print(f"ネットワークエラーのため再試行します... ({attempt + 1}/{self.max_retries})") time.sleep(2 ** attempt) continue else: print(f"ネットワークエラー: {e}") return None except Exception as e: print(f"予期しないエラー: {e}") return None print("最大再試行回数に達しました") return None def _get_request(self, url): """GETリクエスト""" with urllib.request.urlopen(url, timeout=10) as response: if response.status == 200: return json.loads(response.read().decode('utf-8')) else: raise urllib.error.HTTPError( url, response.status, "Request failed", None, None ) def _post_request(self, url, data): """POSTリクエスト""" json_data = json.dumps(data).encode('utf-8') req = urllib.request.Request( url, data=json_data, headers={'Content-Type': 'application/json'} ) with urllib.request.urlopen(req, timeout=10) as response: if response.status in [200, 201]: return json.loads(response.read().decode('utf-8')) else: raise urllib.error.HTTPError( url, response.status, "Request failed", None, None )
# 使用例(実際のAPIエンドポイントではありません)print("=== APIクライアントのデモ ===")print("APIクライアントは以下の機能を持ちます:")print("- 自動リトライ機能")print("- 指数バックオフによる待機時間調整")print("- 各種エラーハンドリング")print("- タイムアウト設定")
# client = APIClient("https://api.example.com")# result = client.make_request("users")# if result:# print(f"APIレスポンス: {result}")
このような実践的な例外処理により、堅牢で信頼性の高いプログラムを作成できます。
まとめ
Python例外処理の基本から実践的な活用方法まで、詳しく解説しました。
今回学んだポイントをおさらい
例外処理の基本
- 実行時エラーに対処するための仕組み
- try-except文でエラーを適切にキャッチ
- プログラムを止めずに継続できる
主要な構文
- try文: エラーが起きる可能性のあるコード
- except文: エラーが起きた時の処理
- else文: エラーが起きなかった時の処理
- finally文: 必ず実行される処理
よく発生する例外
- ValueError, TypeError, IndexError
- KeyError, AttributeError
- FileNotFoundError, PermissionError
- ネットワーク関連の例外
実践的な活用
- ユーザー入力の安全な処理
- ファイル操作の堅牢な実装
- Web APIクライアントのエラーハンドリング
- カスタム例外による詳細なエラー情報
重要なポイント
- with文によるリソース管理
- 適切なログ記録
- リトライ機能の実装
- 予期しないエラーへの対応
例外処理は、プロフェッショナルなプログラム開発において必須のスキルです。 エラーに強い安定したプログラムを作成できるようになります。
まずは基本的なtry-except文から始めて、徐々に複雑なエラーハンドリングに挑戦してみてください。 実際にコードを書いて実行しながら、様々な例外処理パターンを身につけていきましょう。
ぜひ、今日から例外処理を意識したプログラミングを始めてみてくださいね!