Pythonの例外処理(try-except)を使いこなそう
PythonをコマンドプロンプトやPowerShellでPC上で動かすには、Pythonをダウンロードしてインストールする必要があります。
まだの方はPythonのインストールと開発環境の構築の記事を参考にして、Pythonをインストールしてください。
プログラムを書いていると、予期せぬエラーに遭遇することは避けられません。ユーザーの誤った入力、ファイルの不存在、ネットワークの問題など、エラーの原因は様々です。そんな時、プログラムが突然クラッシュしてしまうのを防ぎ、スマートに対応するための仕組みが「例外処理」です。
この記事では、Pythonのtry-except文を使った例外処理の基本から応用まで、コピペしてすぐに動かせるコード例を交えながら、初心者にも分かりやすく解説していきます。「動く」を体験しながら、エラーに強いプログラムの作り方をマスターしましょう!
まずは基本!try-except構文
例外処理の最も基本的な形がtry-except文です。その名の通り、「try(試してみて)、もし例外(エラー)が起きたらexcept(キャッチして対処する)」という流れを作ります。
構文はとてもシンプルです。
tryブロックの中に、エラーが発生する可能性のあるコードを書きます。exceptブロックの中に、エラーが発生した時に実行したいコードを書きます。
百聞は一見にしかず。有名な「ゼロ除算エラー(ZeroDivisionError)」を例に見てみましょう。下のコードでは、10を0で割ろうとしています。通常ならエラーでプログラムが停止してしまいますが、try-exceptでしっかりキャッチします。
<!-- Pythonコード -->
try:
# エラーが発生しそうな処理
result = 10 / 0
print(f"計算結果: {result}")
except ZeroDivisionError:
# ZeroDivisionErrorが発生した場合の処理
print("おっと!0で割ることはできませんよ。")
print("プログラムは正常に終了しました。")
特定の例外を狙い撃ち!複数のexcept
プログラムでは、様々な種類のエラーが発生する可能性があります。例えば、ユーザー入力では「数値を入力してほしいのに文字列が入力された(ValueError)」、ファイル操作では「指定されたファイルが見つからない(FileNotFoundError)」などです。
except文の後にエラーの種類(例外クラス)を指定することで、特定のエラーだけをキャッチして、それぞれに合った処理を行うことができます。
また、exceptを複数並べることで、エラーの種類に応じた処理を書き分けることが可能です。以下の例では、文字列を整数に変換しようとしています。
<!-- Pythonコード -->
user_input = "hello" # 数字ではなく文字
try:
num = int(user_input)
print(f"入力された数値: {num}")
except ValueError:
print("数字を入力してください!文字列は数値に変換できません。")
except TypeError:
print("型が異なります!数値に変換できる型ではありません。")
print("処理を続行します...")
発生したエラーの詳細情報(エラーメッセージ)を知りたい場合も多いでしょう。その場合はasを使って、例外オブジェクトを変数に格納できます。一般的に変数名はe(errorやexceptionの頭文字)がよく使われます。
<!-- Pythonコード -->
try:
# 存在しないファイルを開こうとする
with open("存在しないファイル.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
# エラーの詳細情報を表示
print(f"ファイルが見つかりませんでした。")
print(f"エラー詳細: {e}")
応用編:elseとfinallyを使いこなす
try-exceptには、さらにelseとfinallyという強力な仲間がいます。これらを組み合わせることで、よりきめ細やかな処理が可能になります。
- elseブロック:
tryブロックで例外が発生しなかった場合にのみ実行されます。正常系の処理をエラー処理から明確に分離したいときに便利です。 - finallyブロック: 例外が発生してもしなくても、必ず最後に実行されます。ファイルやネットワーク接続を閉じるなど、後片付け処理を書くのに最適です。
すべての要素を使ったコードを見てみましょう。
<!-- Pythonコード -->
file_path = "my_data.txt"
data_to_write = "これはテストデータです。"
try:
print(f"'{file_path}'にデータを書き込みます...")
f = open(file_path, "w", encoding="utf-8")
# わざとエラーを起こす場合は次の行のコメントを外す
# f.write(12345) # 文字列でないものを書き込もうとするとTypeError
f.write(data_to_write)
print("書き込みを試みました。")
except TypeError as e:
print(f"エラー発生!書き込むデータは文字列である必要があります。")
print(f"エラー詳細: {e}")
except Exception as e:
# 予期せぬその他のエラーをキャッチ
print(f"予期せぬエラーが発生しました。")
print(f"エラー詳細: {e}")
else:
# tryブロックで例外が発生しなかった場合に実行
print("ファイルへの書き込みが成功しました!")
finally:
# 例外の有無にかかわらず、必ず実行
if 'f' in locals() and not f.closed:
f.close()
print("ファイルをクローズしました。")
else:
print("ファイルは開かれていないか、すでにクローズされています。")
print("--- 処理完了 ---")
実践!コピペで動く完全なコード例
それでは、これまでの知識を総動員して、より実践的なプログラムを作ってみましょう。このコードは、ユーザーから年齢を尋ね、有効な数値が入力されるまで繰り返し入力を求めます。そして、入力された年齢をファイルに保存します。途中で発生する可能性のあるエラーをtry-exceptで処理しています。
以下のコードをまるごとコピーして、age_logger.pyのような名前で保存し、ターミナルでpython age_logger.pyと実行してみてください。わざと文字を入力したりして、エラー処理がどう動くか確かめてみましょう!
<!-- Pythonスクリプト全体: age_logger.py -->
import datetime
def record_age():
"""
ユーザーから年齢を尋ね、ファイルに記録する関数。
入力値の検証とファイルI/Oエラーを処理する。
"""
while True:
try:
# ユーザーからの入力を受け取る
age_str = input("あなたの年齢を数字で入力してください: ")
# 文字列を整数に変換
age = int(age_str)
# マイナスの値や非現実的な年齢をチェック
if age < 0 or age > 130:
# 独自のエラーを発生させる (raise)
raise ValueError("年齢は0歳から130歳の間で入力してください。")
# 有効な年齢が入力されたらループを抜ける
break
except ValueError as e:
# int()変換失敗、またはraiseで発生させたValueErrorをキャッチ
print(f"エラー: {e}")
print("もう一度、正しい数値を入力してください。\n")
# ファイルに記録
try:
# with文を使うと自動でファイルがクローズされるので、finallyでclose()が不要になる
with open("age_log.txt", "a", encoding="utf-8") as f:
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"[{timestamp}] 記録された年齢: {age}歳\n")
print(f"あなたの年齢「{age}歳」を'age_log.txt'に記録しました。")
except IOError as e:
# ファイルの書き込み権限がない場合などのエラーをキャッチ
print("致命的なエラー: ファイルへの書き込みに失敗しました。")
print(f"エラー詳細: {e}")
if __name__ == "__main__":
record_age()
print("ご利用ありがとうございました。")
気をつけるべき点:広い範囲での例外キャッチ
例外処理は便利ですが、使い方を誤るとかえってプログラムの問題を発見しにくくすることがあります。特に注意したいのが、広すぎる範囲で例外をキャッチすることです。
非推奨:裸のexcept
最悪の書き方は、例外クラスを指定しない「裸のexcept:」です。これはすべてのエラーを無差別にキャッチしてしまいます。これには、プログラムを終了させるためのSystemExitや、Ctrl+Cで強制停止した際のKeyboardInterruptまでもが含まれます。プログラムを止めたいのに止められなくなる、といった事態になりかねません。
注意が必要:except Exception
except Exception as e:は、裸のexcept:よりは良いですが、それでもほとんどの一般的なエラーをキャッチしてしまいます。開発中は、予期せぬエラー(バグ)を見つけるために、あえてエラーを発生させたい場面も多いです。何でもかんでもキャッチしてしまうと、本来修正すべきバグが隠蔽されてしまう可能性があります。
ベストプラクティスは、「キャッチすることが予測でき、かつ、適切に対処できる例外だけを具体的に指定する」ことです。
まとめと次のステップへ
今回は、Pythonの例外処理try-except文について学びました。ポイントを振り返りましょう。
try-exceptでエラーによるプログラムのクラッシュを防げる。except 例外クラス as eで、特定のエラーを捕まえ、詳細情報を得られる。elseは成功時の処理、finallyは後片付け処理に使う。- 例外のキャッチは、広すぎず、具体的で対処可能なものに絞るのがコツ。
例外処理をマスターすれば、ユーザーにとって親切で、開発者にとってもメンテナンスしやすい、堅牢なアプリケーションを作ることができます。ぜひ、あなたのコードにもtry-exceptを導入してみてください。
次のステップとして、プログラムを部品化し、再利用性を高めるための重要な概念を学んでみませんか?