8日目のゴールとテーマ
8日目のテーマは「エラーとちゃんと付き合える“丈夫なアプリ”にする」です。
ここまでで、かなりいろいろなことができるようになりましたが、まだ弱いところがあります。
それは「想定外の入力」や「ファイルがない」「数字じゃない文字が入ってくる」といった場面です。
今日は次の感覚を身につけることを目標にします。
エラーは“悪”ではなく、「想定外が起きたサイン」だと理解すること。
try と except を使って、落ちないプログラムを書くこと。
入力チェック(バリデーション)を入れて、ユーザーに優しいアプリにすること。
ここまで行けたら、あなたのコードは一気に「実戦向き」になります。
エラーと例外ってそもそも何か
間違ったときにPythonが投げてくる“メッセージ”
まずは「エラー」「例外」という言葉のイメージをそろえます。
Pythonでコードを書いていると、こんなメッセージを見たことがあるはずです。
age = int("abc")
Pythonこれを実行すると、こんなエラーが出ます。
ValueError: invalid literal for int() with base 10: 'abc'
Pythonこれは「’abc’ は整数に変換できません」という意味です。
Pythonは、「このまま続けるとおかしなことになる」と判断したときに、
処理を止めて「例外(exception)」というものを投げます。
大事なのは、例外は「Pythonが怒っている」のではなく、
「ここで問題が起きたよ」と教えてくれているサインだということです。
このサインをちゃんと受け止めて、落ちないようにするのが今日のテーマです。
try と except の基本形
「ここでエラーが出るかもしれない」を囲う
エラーが出そうな場所を安全に実行するために使うのが、try と except です。
まずは一番シンプルな形を見てみましょう。
text = input("整数を入力してください: ")
try:
value = int(text)
print("整数として読み取れました:", value)
except ValueError:
print("整数として読み取れませんでした。数字だけを入力してください。")
Python流れを丁寧に追います。
まずユーザーから文字列として入力を受け取ります。
次に try ブロックの中で int(text) を実行します。
もしここで問題なく整数に変換できれば、そのまま下の print が実行されます。
もし変換できなければ、Pythonは ValueError という例外を投げます。
その瞬間、try ブロックの残りはスキップされて、except ValueError の中にジャンプします。
ここでの超重要ポイントは、「エラーが起きてもプログラム全体は落ちない」ということです。
try の中で失敗しても、except で受け止めて、メッセージを出して処理を続けられます。
except を「なんでもキャッチ」にしない感覚
どのエラーを想定しているのかをはっきりさせる
さっきは except ValueError: と書きました。
これは「ValueError という種類の例外だけを捕まえる」という意味です。
実は、こう書くこともできます。
try:
value = int(text)
except:
print("何かエラーが起きました")
Python一見ラクですが、これはあまりおすすめしません。
理由は、「何が起きたのか分からなくなる」からです。
例えば、まったく別のバグ(変数名の打ち間違いなど)があっても、
全部「何かエラーが起きました」で片付いてしまいます。
デバッグがとてもやりにくくなります。
基本のスタンスとしては、
「どんなエラーが起きうるかを自分で想像して、その種類だけを捕まえる」
という書き方を目指してください。
整数変換なら ValueError。
ファイルがないなら FileNotFoundError。
ゼロで割るなら ZeroDivisionError。
こうやって「想定している失敗」をコードに書いておくと、
読み手にも意図が伝わります。
else と finally で「成功時」「後片付け」を書き分ける
try のあとに続く2つのオプション
try と except に加えて、else と finally というキーワードもあります。
少しだけ踏み込んで見てみましょう。
text = input("整数を入力してください: ")
try:
value = int(text)
except ValueError:
print("整数として読み取れませんでした。")
else:
print("変換に成功しました。値は", value)
finally:
print("このメッセージは、成功しても失敗しても必ず表示されます。")
Pythonそれぞれの役割はこうです。
except は「エラーが起きたとき」に実行される部分。
else は「エラーが起きなかったとき」に実行される部分。
finally は「エラーの有無に関係なく、最後に必ず実行される部分」。
例えば、ファイルを開いて何かして、最後に必ず閉じたいときなどに finally が使われます。
ただ、Pythonでは with 文があるので、ファイルに関してはそちらを使うのが主流です。
else と finally は、「こういう書き分けもできるんだ」と知っておけば今は十分です。
入力バリデーションという考え方
「ユーザーの入力は、基本的に信用しない」前提で設計する
現実のアプリでは、ユーザーが必ずしも「きれいな入力」をしてくれるとは限りません。
数字のところに文字を入れたり、空のまま Enter を押したり、
ときにはわざと変な値を入れてくることもあります。
そこで大事になるのが「入力バリデーション」です。
これは、「入力された値が条件を満たしているかチェックすること」です。
例えば、「年齢は 0 以上 120 以下の整数に限る」と決めたとします。
そのときのコードはこうなります。
def input_age():
while True:
text = input("年齢を入力してください(0〜120): ")
try:
age = int(text)
except ValueError:
print("数字で入力してください。")
continue
if age < 0 or age > 120:
print("0〜120の範囲で入力してください。")
continue
return age
Python流れを丁寧に追います。
while True で「正しい値が入るまでくり返す」ループを作ります。
毎回、文字列として入力を受け取ります。
まず try で int に変換を試みます。
数字でなければ ValueError になり、「数字で入力してください」と表示して continue で次のループに進みます。
整数に変換できたら、今度は範囲チェックをします。
0 未満または 120 より大きければ、「範囲で入力してください」と表示して continue。
どちらも問題なければ、その age を return して関数を終わります。
ここでの超重要ポイントは、「間違った入力を“優しく突き返す”」という姿勢です。
エラーで落とすのではなく、「こう直してね」と伝えて、再入力させる。
これができると、アプリの“人間味”が一気に上がります。
例外を使って「自分でエラーを投げる」
条件を満たさないときに、あえて例外を起こす
ここまでの例では、「Pythonが投げてくる例外」を受け止めていました。
実は、逆に「自分で例外を投げる」こともできます。
def calc_bmi(weight, height):
if height <= 0:
raise ValueError("身長は0より大きい必要があります。")
return weight / (height * height)
Pythonここでは、身長が 0 以下だった場合に、
自分で ValueError を発生させています。
呼び出し側は、これを try で受け止めることができます。
try:
bmi = calc_bmi(60, 0)
print("BMI:", bmi)
except ValueError as e:
print("計算できませんでした:", e)
Python実行すると、「計算できませんでした: 身長は0より大きい必要があります。」と表示されます。
このパターンは、「関数の中で“おかしな状態”を見つけたとき」に使えます。
無理やり計算を続けるのではなく、「ここで止めたほうが安全」と判断して例外を投げる。
そして、もう少し外側のレイヤーで「どう対応するか」を決める。
こうやって、責任の場所を分けていくのが、少し先の設計の世界です。
8日目のミニアプリ:エラーに強いお会計アプリ
入力チェックと例外処理を入れて“落ちない”ようにする
1日目と6日目のお会計アプリを、
「入力バリデーション」と「例外処理」を入れて、かなり丈夫にしてみます。
def input_int(prompt, min_value=None, max_value=None):
while True:
text = input(prompt)
try:
value = int(text)
except ValueError:
print("数字で入力してください。")
continue
if min_value is not None and value < min_value:
print(str(min_value) + "以上の値を入力してください。")
continue
if max_value is not None and value > max_value:
print(str(max_value) + "以下の値を入力してください。")
continue
return value
def input_item():
name = input("商品名を入力してください: ")
price = input_int("1個あたりの値段を入力してください(円): ", min_value=0)
count = input_int("個数を入力してください: ", min_value=1)
return name, price, count
def calc_total(price, count):
return price * count
def print_result(name, count, total):
print("================================")
print("商品名:", name)
print("個数:", count)
print("合計金額:", total, "円")
print("================================")
print("=== お会計アプリ 8日目(エラーに強いバージョン) ===")
try:
item_name, price, count = input_item()
total = calc_total(price, count)
print_result(item_name, count, total)
except Exception as e:
print("予期しないエラーが発生しました。処理を中断します。")
print("エラー内容:", e)
Pythonこのアプリのポイントを整理します。
まず input_int という「整数入力専用の関数」を作っています。
ここで、数字でない入力や範囲外の値をすべて処理して、正しい整数だけを返すようにしています。
input_item は、「商品名」「値段」「個数」をまとめて入力する関数です。
値段は 0 以上、個数は 1 以上というルールを input_int の引数で表現しています。
メインの部分では、全体を大きな try で囲んでいます。
ここではあえて except Exception で「予期しないエラー」をまとめて捕まえています。
理由は、「どこかにバグがあっても、ユーザーに“真っ白で落ちる”体験をさせないため」です。
本当はログを残したり、開発中はそのままエラーを出したりといろいろありますが、
今日は「最悪のときでもメッセージを出して終われる」という感覚が持てれば十分です。
8日目で一番大事な感覚
「エラーは“敵”ではなく、“対話すべき相手”」
今日あなたに持ってほしい感覚はこれです。
エラーは「ダメな証拠」ではありません。
むしろ、「ここに想定外があるよ」と教えてくれる、ありがたい存在です。
try と except で「ここは失敗するかもしれない」と認める。
入力バリデーションで「ここまでは許すけど、ここから先はダメ」とルールを決める。
必要なら自分で raise して、「ここで止めたほうが安全」と判断する。
こうやってエラーと対話できるようになると、
あなたのアプリは「動けばいい」から「壊れにくい」に変わっていきます。
8日目のまとめ
今日のキーポイントを短くまとめると、こうなります。
例外は「おかしな状態が起きたサイン」で、try と except で受け止められる。
ValueError や FileNotFoundError など、「どんなエラーを想定しているか」を明示するのが大事。
入力バリデーションで、「数字かどうか」「範囲内かどうか」をチェックする。
while と try を組み合わせて、「正しい値が入るまで聞き続ける」パターンは超重要。
必要に応じて raise で自分から例外を投げることで、「ここで止める」という判断もコードにできる。
もし余裕があれば、7日目のファイル付き名簿アプリにも、
入力バリデーションと try/except を組み込んでみてください。
年齢が変な値だったら登録しない、ファイルが壊れていたらスキップする、など。
そこまでできたら、あなたのアプリはもう「練習用」ではなく、
ちゃんと“壊れにくい小さなプロダクト”になっています。
