- プログラムがエラーで頻繁に止まってしまう。
- エラーが発生したときにログを残したい。
こんな悩みを解決します。
Pythonを使った開発で避けて通れないのが例外(Exception)です。
この処理を正しく行うことで、プログラムの安定性と信頼性を大幅に向上させることができます。
この記事では、try-except文を使った例外処理方法を、初心者にもわかりやすく解説します。
この記事を読み進めれば、例外(Exception)の処理方法がわかるだけでなく、プログラムの安定性を向上させられます。
Pythonの例外処理の基本
例外とは、実行中に発生するエラーのこと
例外(Exception)とは、プログラムの実行中に発生する予期せぬエラーや異常事態を指します。
例えば、ゼロで割る計算を試みたり、存在しないファイルを開こうとしたりした場合に、例外が発生します。
例外が発生すると、プログラムは通常の実行を中断するため、何らかの対処が必要になります。
エラーには例外(Exception)と構文エラー(SyntaxError)があります。
構文エラーとは、プログラムの文法ルールに違反した場合に発生するエラーです。
構文エラーについてはこちらの記事で解説しています。
⇒【Python構文エラー完全攻略】SyntaxErrorの原因と解決方法を解説!
例外処理とは、エラー発生時に適切な処理をすること
例外処理とは、プログラム実行中に予期せぬエラーが発生した際に、そのエラーを捕捉し、適切な処理を行うことです。
例外処理の目的は次の通りです。
- プログラムの異常終了を防ぎ、ユーザーに安心して使ってもらうこと。
- エラーの詳細をログに記録してデバッグやメンテナンスを容易にすること。
- 必要に応じて、エラー発生時に代替処理を実行すること。
適切に処理することで、プログラムの安定性を高めることができます。
Pythonの公式ドキュメントで、例外処理の基本的な使い方について解説されています。
例外の種類
主な例外には次のものがあります。
- ZeroDivisionError:ゼロで除算しようとした場合
- ValueError:数値として扱えない値が入力された場合
- NameError:未定義の変数にアクセスしようとした場合
- TypeError:データ型が異なる値に対して演算を行おうとした場合
- FileNotFoundError:存在しないファイルを開こうとした場合
- IndexError:リストやタプルの範囲外のインデックスにアクセスしようとした場合
- KeyError:辞書に存在しないキーにアクセスしようとした場合
他にも様々な例外が存在します。
どのような例外があるかは、公式サイトで確認することができます。
例外処理の基本構文
Pythonでは、try、except、else、finally文を使用して例外を処理します。
try-except
基本的な例外処理方法です。
try:
# 例外が発生する可能性のあるコード
except {例外}:
# 例外が発生した場合の処理
try文の下には、例外が発生する可能性のあるコードを記入します。
{例外}には、処理したい例外名(ZeroDivisionError、ValueErrorなど)を記入します。指定した例外が発生した場合のみ、except文の処理を行います。
処理の流れは次の通りです。
- try文に記入されたコードが最初に実行されます。
- try文内で例外が発生しなかった場合、except文のコードがスキップされ、try文全体の処理が終了します。
- 例外が発生した場合、try文の残りの処理が中断されます。発生した例外が、except文で指定した例外と一致していれば、except文のコードが実行されます。except文の処理が終了後、try-exceptの処理が完了します。
- 発生した例外が、except文で指定した例外と一致していない場合、except文はスキップされ、try-exceptの処理が終了します。他に例外処理するコードがなければ、未処理の例外により、エラーメッセージを表示して、プログラムは停止します。
プログラムで実際に使用する方法を紹介します。
「ZeroDivisionError」を処理する場合
try:
x = 10 / 0 # ゼロ除算
except ZeroDivisionError:
print("ゼロ除算エラーが発生しました。数値を確認してください。")
すべての例外を受け取る場合
try:
risky_code()
except Exception as e:
print(f"エラーが発生しました: {e}")
try-except-else
例外が発生しなかった時に、特定の処理を実行する場合はelse文を使用します。
try:
# 例外が発生する可能性のあるコード
except {例外}:
# 例外が発生した場合の処理
else:
# 例外が発生しなかった場合の処理
else文がないと、例外が発生しなかった場合、try文のコードのみ実行して終了します。
else文は例外の有無で処理を分けた場合に活用できます。
プログラム例
try:
result = 10 / 2
except ZeroDivisionError:
print("エラーが発生しました。")
else:
print("計算成功:", result)
try-except-finally
例外の発生に関わらず、特定の処理を必ず実行する場合はfinally文を使用します。
try:
# 例外が発生する可能性のあるコード
except {例外}:
# 例外が発生した場合の処理
finally:
# 例外の発生に関わらず、特定の処理を必ず実行する場合の処理
finally文には次の特徴があります。
- tryブロック内でreturn、break、continueが実行された場合でも、必ずfinally内の処理が実行されます。
- 例外が発生してもしなくても、必ず実行されます。
- プログラムがtryブロック内で強制終了(sys.exit()など)された場合でも実行されます。
finally文は必ず実行されるべき処理がある場合に使用します。
例えば次の処理を行うときに、finally文の使用をおすすめします。
- ファイルのクローズ
- データベース接続の切断
- ロックの解放
- 一時的なリソースの解放
プログラム例
try:
file = open("example.txt", "r")
except FileNotFoundError:
print("ファイルが見つかりません。")
finally:
if 'file' in locals() and not file.closed:
file.close()
print("ファイルを閉じました。")
assert文:条件を検証する
assert文は、プログラムの前提条件や後続条件を検証するときに使用します。
assert文を使用することで、条件が満たされていない場合に即座にエラーを通知でき、開発段階でのバグ修正が容易になります。
基本的な構文は次の通りです。
assert 条件式, "エラーメッセージ(省略可能)"
条件式がFalseのとき、エラーメッセージを出力し、その後プログラムが停止します。
プログラム例
def divide(a, b):
assert b != 0, "ゼロでは割り算できません。"
return a / b
print(divide(10, 2)) # 正常動作
print(divide(10, 0)) # AssertionError
Pythonでは、-Oオプションを付けて実行すると、assert文が無効化されます。無効化された場合、assert文はスキップされるため、必須の検証には使用しないことが推奨されます。assert文はデバッグのみで使用しましょう。
raise文:意図的に例外を発生させる
例外処理をより柔軟に行う方法として、raise文があります。raise文は意図的に例外を発生させることができます。
raise文は3つの使い方があります。
- 意図的にエラーを発生させたいとき
- 独自のカスタム例外を定義したいとき
- エラーを再スローして上位のハンドラに処理させたいとき
意図的にエラーを発生させたいとき
raise文の基本的な構文は次の通りです。
raise {例外}("エラーメッセージ")
{例外}には、Pythonの組み込み例外クラスを記入します。(例:ValueError, TypeError, IndexErrorなど)。
エラーメッセージには、例外が発生した際に表示されるメッセージを入力します。エラー内容が分かるメッセージにすることで、デバッグに役立ちます。
独自のカスタム例外を定義したいとき
raise文は、標準の組み込み例外クラスでは表現できないような、より具体的な例外を発生することができます。
class {カスタム例外クラス}(Exception):
pass
raise {カスタム例外クラス}("エラーメッセージ")
上記のコードでは、Exceptionクラスを継承して、カスタム例外を定義しています。
カスタム例外を定義してあれば、raise文の使用方法は、基本と同じです。
プログラム例
class DataValidationError(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)
def validate_age(age):
if not isinstance(age, int):
raise DataValidationError("年齢は整数で指定してください")
if age < 0:
raise DataValidationError("年齢は0以上である必要があります")
カスタム例外を定義する際、エラーコードや詳細情報を保持する場合は次のように記述することもできます。ここでは、エラーメッセージとエラーコードを保持しています。
class {カスタム例外クラス}(Exception):
def __init__(self, message, error_code=None):
self.message = message
self.error_code = error_code
super().__init__(f"{message} (Error Code: {error_code})")
エラーを再スローして上位のハンドラに処理させたいとき
try-exceptで捕捉した例外を再度発生させることで、上位のハンドラに処理を委譲することができます。
シンプルな再スローは次のように記述します。ここでは、受け取ったエラーを変更せず、再度発生させています。
try:
# 例外が発生する可能性のあるコード
except {例外}:
# 例外が発生した場合の処理
raise # 同じ例外を再スロー
プログラム例
try:
result = 1 / 0
except ZeroDivisionError as e:
print("エラーをログに記録")
raise # 同じ例外を再スロー
受け取った例外とは別の例外を発生させることもできます。
try:
# 例外が発生する可能性のあるコード
except {例外} as e:
# 例外が発生した場合の処理
raise 新しい例外 from e # 新しい例外を発生させ、元の例外を原因として設定
raise文による再スローは、次のケースで活用することができます。
- エラーのログ記録後に例外を伝播させたい場合
- エラーの種類を変換したい場合
- 追加の情報やコンテキストを付加したい場合
複数の例外処理
複数の例外処理をするには次の方法があります。
- 複数のexcep文による処理
- 1つのexcept文による処理
複数のexcept文による処理
複数のexcept文で例外処理をする場合は、次のように記述します。
try:
x = 10 / 0 # ゼロ除算
with open("non_existent_file.txt", "r") as file:
content = file.read() # ファイル読み込みエラー
except ZeroDivisionError:
print("ゼロ除算エラーが発生しました。数値を確認してください。")
except FileNotFoundError:
print("指定されたファイルが見つかりませんでした。")
except Exception as e:
print(f"その他のエラーが発生しました: {e}")
except文は上から順に評価され、最初に一致するexcept文が実行されます。
具体的な例外(例えばZeroDivisionError)を先に記述し、汎用的な例外(例えばException)を後に記述するのが一般的です。
1つのexcept文による処理
1つのexcept文で例外処理することも可能です。
try:
# 何らかの処理
pass
except (ValueError, TypeError) as e:
print(f"値または型のエラーが発生: {e}")
複数の例外をタプル型で指定します。
1つのexcept文で処理する場合、複数の例外に対して、同じ処理を行います。
例外ごとに処理を変えるには、except文を複数用意する必要があります。
例外処理をする時の注意点
広範囲な例外キャッチを避ける
例外処理を書く際に、except Exception: のようにすべての例外を一括でキャッチするコードは避けましょう。
except Exception: を使用すると、予期せぬ例外もすべて捕捉してしまい、問題の根本原因を見逃すリスクがあります。
具体的な例外を指定することで、エラーの特定とデバッグが容易になります。
例外のログ記録を忘れない
例外が発生した場合、その詳細を記録することは非常に重要です。
ログを残さないと、後から原因を追跡することが困難になるだけでなく、同様のエラーが再発した際の対応も遅れる可能性があります。
Pythonでは、loggingモジュールを使うことで簡単にログを記録できます。
例えば、ログを出力する形式やレベルを適切に設定すれば、エラーの内容を詳細に把握でき、後続の分析や改善に役立てることができます。
プログラム例
import logging
logging.basicConfig(level=logging.ERROR)
try:
# 何らかの処理
except Exception as e:
logging.error("エラーが発生しました", exc_info=True)
エラーを隠さず適切に再スローする
例外をキャッチした際、エラーをそのまま無視するのではなく、適切に再スローすることが重要です。
エラーを隠してしまうと、システム全体の異常を見逃す可能性があります。特に、例外が重大な問題を引き起こす場合は、正しいエラーメッセージを上流のコードやシステム管理者に伝える必要があります。
例えば、例外をキャッチした後に補足的な処理を行ったり、エラーメッセージに追加情報を付与することで、デバッグや修正が容易になります。これにより、システムの安定性を損なうことなく、柔軟なエラー対応が可能になります。
実践的な例外処理パターン
ファイル操作時の例外処理
ファイルの読み書き時には、ファイルが存在しない場合や権限エラーが発生する可能性があります。
以下は安全にファイルを操作する例です。
try:
with open('example.txt', 'r') as file:
data = file.read()
except FileNotFoundError:
print("ファイルが見つかりませんでした。")
except PermissionError:
print("ファイルのアクセス権限がありません。")
FileNotFoundError
はファイルが見つからない場合に発生します。
たとえば、指定したパスが間違っている場合やファイルが削除されている場合にこのエラーが発生します。
一方、PermissionError
は、読み取ろうとしているファイルに対してアクセス権限がない場合に発生します。
このような例外を捕捉することで、ユーザーに適切なエラーメッセージを提供しつつ、プログラムの予期せぬ終了を防ぎます。
データベース接続時の例外処理
データベースに接続する際は、接続失敗やクエリエラーを考慮します。
import sqlite3
try:
connection = sqlite3.connect('example.db')
cursor = connection.cursor()
cursor.execute("SELECT * FROM users")
results = cursor.fetchall()
except sqlite3.DatabaseError as e:
print(f"データベースエラー: {e}")
finally:
if connection:
connection.close()
sqlite3.DatabaseError
は、データベース接続が失敗した場合やSQLクエリの文法が間違っている場合に発生します。
この例では、finally
ブロックを使用してデータベース接続を閉じています。
これにより、例外が発生した場合でもリソースリークを防ぐことができます。
安全なデータベース操作には、このようなリソース管理が不可欠です。
API通信時の例外処理
外部APIにリクエストを送信する場合、タイムアウトや通信エラーへの対応が必要です。
import requests
try:
response = requests.get('https://api.example.com/data', timeout=5)
response.raise_for_status()
data = response.json()
except requests.exceptions.HTTPError as e:
print(f"HTTPエラー: {e}")
except requests.exceptions.RequestException as e:
print(f"通信エラー: {e}")
外部APIに接続する際には、さまざまな問題が発生する可能性があります。
たとえば、サーバーがダウンしている場合や、クライアント側のネットワーク接続が不安定な場合です。
HTTPError
は、リクエストが成功しなかった場合(例:404 Not Found、500 Internal Server Errorなど)に発生します。
RequestException
はさらに広範囲のエラーを捕捉し、通信失敗やタイムアウトをハンドリングします。
これにより、エラーが発生しても適切に処理し、ユーザーに有用な情報を提供できます。
ユーザー入力処理時の例外処理
ユーザー入力を処理する際には、適切なデータ型であるかをチェックすることが重要です。
try:
user_input = int(input("数字を入力してください: "))
print(f"入力された数字は {user_input} です。")
except ValueError:
print("有効な数字を入力してください。")
ユーザーが入力したデータが期待する形式でない場合、ValueError
が発生します。
たとえば、文字列「abc」を入力すると整数に変換できないため、例外がスローされます。
この例では、例外を捕捉してエラーメッセージを表示することで、ユーザーに再入力を促すことができます。
ユーザーインターフェースを改善し、プログラムの堅牢性を向上させるためには、入力のバリデーションが不可欠です。
Q&A
例外処理ってなに?
例外処理とは、プログラム実行中に予期せぬエラーが発生した際に、そのエラーを捕捉し、適切な処理を行うことです。
適切に処理することで、プログラムの安定性を高めることができます。
例外処理はどのように書けばいいの?
例外処理の基本構文は次の通りです。
try: # 例外が発生する可能性のあるコード except {例外}: # 例外が発生した場合の処理
複数種類のエラーを処理するにはどうすればいいの?
exceptを複数書くか、一つのexceptで複数のエラーをタプルで指定します。
まとめ
この記事では、try-except文を使った例外処理方法を、初心者にもわかりやすく解説しました。
例外処理をする時は下記コマンドを使用します。
- try-except
- try-except-else
- try-except-finally
より高度な処理を行う場合は、assert文やraise文を使用します。
例外処理を適切に行うことで、プログラムの安定性や信頼性が向上します。
この記事を何度も読み返して、例外処理を習得してください。
Pythonを効率的に学習するために
Pythonの学習方法は、書籍やyoutube、スクールなどがありますが、一番のおすすめはオンラインスクールでの学習です。
オンラインスクールを勧める理由は以下の通り。
- 学習カリキュラムが整っているので、体系的に学ぶことができる。
- 時間や場所を選ばずに、自分のペースで学習できる。
- 学習で詰まったときに、気軽に質問できる環境がある。
オンラインスクールについてはコチラの記事で紹介しています。
⇒ これで決まり!Pythonオンラインスクール おすすめ3社を厳選!
2024年10月1日から給付制度が拡充され、最大80%給付されるスクールもあります。
Python学習を効率的に進めるために、スクールの検討をしてみてください。
おすすめオンラインスクール
コスト重視:デイトラ
AIスキル重視:Aidemy PREMIUM
転職重視:キカガク
最後まで読んでいただきありがとうございます!
ご意見、ご感想があれば、コメントを頂けるとうれしいです!!