4日目のゴール
4日目のテーマは
「try / except を“設計レベル”で使い、エラー処理をコードの一部としてきれいに組み込む」 ことです。
ここまでであなたはすでに、
入力エラーを落とさず処理できる
安全な入力関数を作れる
ファイル読み書きに try / except を使える
というところまで来ています。
4日目では一歩進んで、
エラー処理の「責任範囲」をはっきり分ける
「ここでは例外を握りつぶさない」という判断を学ぶ
アプリ全体の流れとエラー処理をきれいに共存させる
という、“中級者のエラーハンドリングの感覚” を育てます。
エラー処理には「3つのレベル」があると考える
レベル1:その場で対処して終わるエラー
例えば、整数入力のときの ValueError。
def input_int(prompt):
while True:
text = input(prompt)
try:
value = int(text)
except ValueError:
print("数字で入力してください。")
continue
return value
Pythonこのレベルのエラーは、
ユーザーにメッセージを出す
やり直させる
それで完結する
という「その場完結型」です。
ここでは、例外を上に投げる必要はありません。try / except の中で完結させてOKです。
レベル2:その場では判断できないエラー(上に投げたい)
例えば、ファイル読み込み関数の中での OSError。
def load_text(filename):
with open(filename, "r", encoding="utf-8") as f:
return f.read()
Pythonここで FileNotFoundError や PermissionError が起きたとき、
「どうするか」は関数の中だけでは決めきれないことがあります。
空文字として扱うのか
「ファイルがないので新規作成します」とするのか
アプリ全体を終了させるのか
これは、アプリの設計レベルの判断です。
この場合は、あえてここでは try / except を書かず、
「例外を上に投げる」 という選択も大事です。
レベル3:アプリ全体の「最後の砦」としてのエラーハンドリング
一番外側、例えば main() の中で、
「ここまで来た例外は、もうアプリ全体として扱う」
という場所を作るのも、設計としてとても重要です。
def main():
try:
run_app()
except Exception as e:
print("予期しないエラーが発生しました。アプリを終了します。")
print(f"詳細: {e}")
Pythonここは、
「本来は下の層で処理されるべきだったけど、漏れてきたエラー」を
最後に受け止める場所です。
4日目では、この「どのレベルで処理するか」を意識して
try / except を配置していきます。
「握りつぶす」と「投げる」を意識して選ぶ
なんでもかんでも except で終わらせると危険
悪い例をあえて出します。
def load_text(filename):
try:
with open(filename, "r", encoding="utf-8") as f:
return f.read()
except Exception:
return ""
Python一見「安全そう」に見えますが、
これはかなり危険です。
ファイルが存在しない
権限がない
ディスクが壊れている
パスの指定ミス
プログラミングミス(例えば filename が None)
全部まとめて「空文字にする」ことになります。
本来は気づくべきバグまで飲み込んでしまい、
「なぜかデータが空になるアプリ」になってしまいます。
「ここでは処理しない」という勇気を持つ
例えば、こういう分け方が健全です。
def load_text_raw(filename):
with open(filename, "r", encoding="utf-8") as f:
return f.read()
Pythonこの関数は、あえて try / except を書きません。
「ファイル読み込みに失敗したら例外を投げる関数」として定義します。
そして、使う側で方針を決めます。
def load_text_safe(filename):
try:
return load_text_raw(filename)
except FileNotFoundError:
print("ファイルがありません。新規として扱います。")
return ""
except PermissionError:
print("ファイルを読む権限がありません。")
return ""
Pythonここでの本質は、
「例外をどこで処理するか」を意識的に決める
「下の層では投げるだけ、上の層で方針を決める」という分業をする
という設計の考え方です。
入力アプリに「ビジネスルールのエラー」を足してみる
型エラーと「意味としておかしい」エラーを分ける
例えば、簡単な「予約人数入力アプリ」を考えます。
仕様はこうです。
人数は整数
1〜10人まで
それ以外はエラー
まずは素朴に書くとこうなります。
def input_people_count():
while True:
text = input("人数を入力してください(1〜10): ")
try:
value = int(text)
except ValueError:
print("数字で入力してください。\n")
continue
if not (1 <= value <= 10):
print("1〜10の範囲で入力してください。\n")
continue
return value
PythonこれはこれでOKです。
ただ、ここには二種類のエラーが混ざっています。
文字列 → 整数変換の失敗(技術的なエラー)
1〜10の範囲外(ビジネスルールのエラー)
この二つを意識して分けておくと、
アプリが大きくなったときに整理しやすくなります。
「意味としておかしい」エラーを例外として扱う
少しだけ踏み込んでみましょう。
class BusinessRuleError(Exception):
pass
def validate_people_count(value):
if not (1 <= value <= 10):
raise BusinessRuleError("人数は1〜10の範囲でなければなりません。")
Pythonそして、入力関数側ではこう使います。
def input_people_count():
while True:
text = input("人数を入力してください(1〜10): ")
try:
value = int(text)
validate_people_count(value)
except ValueError:
print("数字で入力してください。\n")
continue
except BusinessRuleError as e:
print(str(e) + "\n")
continue
return value
Pythonここでの重要ポイントは、
技術的なエラー(ValueError)と
ビジネスルールのエラー(BusinessRuleError)を
別の例外として扱っていることです。
これにより、
ログに残すときに区別できる
上の層で「どの種類のエラーか」を見て振る舞いを変えられる
という柔軟さが生まれます。
4日目の段階では「こういう分け方もあるんだ」と知っておけば十分です。
アプリ全体の「エラーの流れ」を設計する
小さな入力アプリでも「流れ」を意識してみる
次のようなアプリを考えます。
年齢を入力(1〜120)
月収を入力(0以上)
年収を計算して表示
ここに、try / except を設計的に組み込みます。
class BusinessRuleError(Exception):
pass
def input_int(prompt):
while True:
text = input(prompt)
try:
value = int(text)
except ValueError:
print("数字で入力してください。\n")
continue
return value
def input_age():
while True:
age = input_int("年齢を入力してください(1〜120): ")
try:
if not (1 <= age <= 120):
raise BusinessRuleError("年齢は1〜120の範囲で入力してください。")
except BusinessRuleError as e:
print(str(e) + "\n")
continue
return age
def input_monthly_income():
while True:
income = input_int("月収を入力してください(0以上): ")
try:
if income < 0:
raise BusinessRuleError("月収は0以上で入力してください。")
except BusinessRuleError as e:
print(str(e) + "\n")
continue
return income
def run_app():
age = input_age()
income = input_monthly_income()
yearly = income * 12
print(f"\nあなたの年齢は {age} 歳、推定年収は {yearly} です。")
def main():
try:
run_app()
except Exception as e:
print("予期しないエラーが発生しました。アプリを終了します。")
print(f"詳細: {e}")
main()
Pythonここでの構造を整理すると、
input_int は「技術的なエラー(ValueError)」だけを扱うinput_age / input_monthly_income は「意味としておかしい値」を扱うrun_app は「アプリの本来の処理」に集中するmain は「最後の砦」として、漏れてきた例外をまとめて扱う
という役割分担になっています。
4日目のミニアプリ:メニュー+入力+ファイル+エラー設計をまとめる
小さくても「設計されたエラーハンドリング」を体験する
仕様はこうです。
簡単な「支出記録アプリ」
メニューで「1: 支出を追加」「2: 合計を見る」「0: 終了」
金額は整数、0以上
ファイル expenses.txt に1行1金額で保存
ファイルがなくても落ちない
入力・ファイル・メニュー、それぞれに適切な try / except
コードの骨格はこんな感じになります。
import os
FILENAME = "expenses.txt"
class BusinessRuleError(Exception):
pass
def input_int(prompt):
while True:
text = input(prompt)
try:
value = int(text)
except ValueError:
print("数字で入力してください。\n")
continue
return value
def input_amount():
while True:
amount = input_int("金額を入力してください(0以上): ")
try:
if amount < 0:
raise BusinessRuleError("金額は0以上で入力してください。")
except BusinessRuleError as e:
print(str(e) + "\n")
continue
return amount
def append_expense(amount):
try:
with open(FILENAME, "a", encoding="utf-8") as f:
f.write(str(amount) + "\n")
except OSError:
print("ファイルに書き込めませんでした。")
def load_expenses():
if not os.path.exists(FILENAME):
return []
try:
with open(FILENAME, "r", encoding="utf-8") as f:
lines = f.readlines()
except OSError:
print("ファイルを読み込めませんでした。")
return []
expenses = []
for line in lines:
line = line.strip()
if line == "":
continue
try:
value = int(line)
except ValueError:
print(f"不正な行をスキップしました: {line}")
continue
expenses.append(value)
return expenses
def run_app():
while True:
print("\n=== 支出記録アプリ ===")
print("1: 支出を追加")
print("2: 合計を見る")
print("0: 終了")
choice = input_int("番号を選んでください: ")
if choice == 1:
amount = input_amount()
append_expense(amount)
print("支出を記録しました。")
elif choice == 2:
expenses = load_expenses()
total = sum(expenses)
print(f"これまでの合計支出は {total} です。")
elif choice == 0:
print("終了します。")
break
else:
print("その番号のメニューはありません。\n")
def main():
try:
run_app()
except Exception as e:
print("予期しないエラーが発生しました。アプリを終了します。")
print(f"詳細: {e}")
main()
Pythonここまで来ると、
入力エラー
ビジネスルールエラー
ファイルエラー
予期しないエラー
それぞれに対して、
「どこで」「どう扱うか」がはっきり分かれています。
4日目で絶対に押さえてほしい本質
try / except は「設計の一部」になる
今日いちばん大事なのは、
try / except を
「とりあえず落ちないようにするための道具」から
「どの層で何を責任を持つかを表現するための道具」
として捉え直すことです。
どこで例外を投げるか
どこで例外を捕まえるか
どの例外は握りつぶしてよくて
どの例外は上に伝えるべきか
これを意識して書き始めた瞬間、
あなたのコードはもう「中級者の設計」に入っています。
5日目以降は、この感覚を
JSON保存アプリやより複雑な入力フローに重ねていきます。
今日の支出アプリを、自分なりに機能追加しながら、
「このエラーはどこで扱うのが気持ちいいか」を探ってみてください。


