Python | 1 日 120 分 × 7 日アプリ学習:エラーハンドリング付き入力アプリ(中級編)

Web APP Python
スポンサーリンク

2日目のゴール

2日目のテーマは
「try / except を“使い回せる形”にして、複数入力のアプリを安全にする」 ことです。

1日目は「1つの入力を安全に受け取る」ことに集中しました。
2日目はそこから一歩進んで、

複数の値(例:身長と体重)を安全に入力させる
同じエラーハンドリングを関数として再利用する
try / exceptelsefinally を組み合わせる

という「一段階大人な使い方」を身につけます。


1日目の復習を“関数目線”で捉え直す

「安全な整数入力」をひとつの部品にする

1日目の年齢入力は、こんな形でした。

def input_age():
    while True:
        age_text = input("年齢を入力してください: ")

        try:
            age = int(age_text)
        except ValueError:
            print("数字で入力してください。\n")
            continue

        if age <= 0:
            print("0より大きい数を入力してください。\n")
            continue

        return age
Python

ここでやっていることを、もう一段抽象化してみます。

「整数を入力してもらう」
「数字以外ならやり直し」
「条件(0より大きいなど)を満たさなければやり直し」

これって、年齢だけじゃなくて
「人数」「点数」「在庫数」など、いろんな場面で使えます。

つまり、

「安全な整数入力」そのものを、汎用的な関数にできる

ということです。


汎用的な「安全な整数入力関数」を作る

メッセージと条件を引数で渡す

「整数を安全に入力させる」関数を、
どんな場面でも使えるように設計してみます。

def input_int(prompt):
    while True:
        text = input(prompt)

        try:
            value = int(text)
        except ValueError:
            print("数字で入力してください。\n")
            continue

        return value
Python

これで、

age = input_int("年齢を入力してください: ")
count = input_int("個数を入力してください: ")
score = input_int("点数を入力してください: ")
Python

のように、同じ関数を何度でも使えます。

ここでの重要ポイントは、

「何を聞くか」は prompt に任せる
「整数に変換する」「数字以外ならやり直し」は関数側が担当する

という役割分担です。


条件付きの整数入力に発展させる

「0より大きい」「0以上100以下」などをチェックする

現実のアプリでは、

年齢は 1 以上
点数は 0〜100
人数は 1 以上

のように、「整数なら何でもOK」ではないことが多いです。

そこで、「条件をチェックする関数」を受け取る形にしてみます。

def input_int_with_check(prompt, check_func, error_message):
    while True:
        text = input(prompt)

        try:
            value = int(text)
        except ValueError:
            print("数字で入力してください。\n")
            continue

        if not check_func(value):
            print(error_message + "\n")
            continue

        return value
Python

使う側は、こう書きます。

age = input_int_with_check(
    "年齢を入力してください: ",
    lambda v: v > 0,
    "0より大きい数を入力してください。"
)

score = input_int_with_check(
    "点数を入力してください: ",
    lambda v: 0 <= v <= 100,
    "0〜100の範囲で入力してください。"
)
Python

ここで深掘りしたいのは、

check_func という「条件判定の関数」を引数で渡していること
try / except は「型変換の失敗」にだけ集中していること

です。

try / except の役割はあくまで
「文字列 → 整数」の変換に失敗したときの対応であり、
「値として妥当かどうか」は別のレイヤーでチェックする、
という分け方がとても大事です。


具体例:BMI計算アプリをエラーハンドリング付きで作る

まずは「危険な」バージョン

身長と体重からBMIを計算するアプリを考えます。

height_text = input("身長(cm)を入力してください: ")
weight_text = input("体重(kg)を入力してください: ")

height_cm = float(height_text)
weight = float(weight_text)

height_m = height_cm / 100
bmi = weight / (height_m ** 2)

print(f"BMIは {bmi:.1f} です。")
Python

ここには、いくつも危険があります。

数字以外を入れたときの ValueError
身長に 0 やマイナスを入れたときの「おかしな計算」
体重に 0 やマイナスを入れたときの「おかしな計算」


「安全な float 入力関数」を作る

整数と同じように、
小数も安全に入力させる関数を作ります。

def input_float_with_check(prompt, check_func, error_message):
    while True:
        text = input(prompt)

        try:
            value = float(text)
        except ValueError:
            print("数字(小数も可)で入力してください。\n")
            continue

        if not check_func(value):
            print(error_message + "\n")
            continue

        return value
Python

これを使って、BMIアプリを書き直します。

def main():
    height_cm = input_float_with_check(
        "身長(cm)を入力してください: ",
        lambda v: v > 0,
        "身長は0より大きい値を入力してください。"
    )

    weight = input_float_with_check(
        "体重(kg)を入力してください: ",
        lambda v: v > 0,
        "体重は0より大きい値を入力してください。"
    )

    height_m = height_cm / 100
    bmi = weight / (height_m ** 2)

    print(f"BMIは {bmi:.1f} です。")

main()
Python

ここでの重要ポイントは、

try / except は「floatに変換できるかどうか」だけを見ている
「0より大きいかどうか」は check_func に任せている

という、責務の分離です。


try / except に else を組み合わせる

「エラーがなかったときだけやりたい処理」を分ける

try / except には、実は else をつけることができます。

基本形はこうです。

try:
    危険な処理
except エラーの種類:
    エラー時の処理
else:
    エラーが起きなかったときの処理
Python

BMIの一部を例にすると、こう書けます。

text = input("身長(cm)を入力してください: ")

try:
    height_cm = float(text)
except ValueError:
    print("数字で入力してください。")
else:
    print(f"あなたの身長は {height_cm} cm ですね。")
Python

else の意味は、

「try の中で例外が起きなかった場合だけ、ここを実行する」

です。

正直、初心者のうちは else を使わなくても書けますが、
「エラー処理」と「成功時の処理」を視覚的に分けられるので、
コードが読みやすくなります。


try / except に finally を組み合わせる

「エラーの有無に関係なく、最後に必ずやること」

finally は、こういうときに使います。

ファイルを開いたら、最後に必ず閉じたい
一時的なメッセージを消したい
ログを必ず書きたい

基本形はこうです。

try:
    危険な処理
except エラーの種類:
    エラー時の処理
else:
    エラーがなかったときの処理
finally:
    最後に必ずやる処理
Python

入力アプリでは出番は少なめですが、
イメージだけ持っておきましょう。

例えば、こんな感じです。

def demo():
    print("入力を開始します。")
    try:
        value = int(input("数字を入力してください: "))
    except ValueError:
        print("数字ではありませんでした。")
    else:
        print(f"入力された数字は {value} です。")
    finally:
        print("入力処理を終了します。")

demo()
Python

ここで finally は、
エラーがあってもなくても「終了メッセージ」を出しています。


2日目のミニアプリ:身長・体重・年齢を安全に受け取るプロフィール入力

3つの入力を全部「落ちない」ようにする

仕様はこうです。

年齢(整数、1以上)
身長(cm、小数、0より大きい)
体重(kg、小数、0より大きい)

全部を安全に入力させて、
最後にプロフィールとして表示する。

コードはこうなります。

def input_int_with_check(prompt, check_func, error_message):
    while True:
        text = input(prompt)

        try:
            value = int(text)
        except ValueError:
            print("数字で入力してください。\n")
            continue

        if not check_func(value):
            print(error_message + "\n")
            continue

        return value

def input_float_with_check(prompt, check_func, error_message):
    while True:
        text = input(prompt)

        try:
            value = float(text)
        except ValueError:
            print("数字(小数も可)で入力してください。\n")
            continue

        if not check_func(value):
            print(error_message + "\n")
            continue

        return value

def main():
    age = input_int_with_check(
        "年齢を入力してください: ",
        lambda v: v > 0,
        "年齢は0より大きい数で入力してください。"
    )

    height_cm = input_float_with_check(
        "身長(cm)を入力してください: ",
        lambda v: v > 0,
        "身長は0より大きい値を入力してください。"
    )

    weight = input_float_with_check(
        "体重(kg)を入力してください: ",
        lambda v: v > 0,
        "体重は0より大きい値を入力してください。"
    )

    print("\n=== プロフィール ===")
    print(f"年齢: {age} 歳")
    print(f"身長: {height_cm} cm")
    print(f"体重: {weight} kg")

main()
Python

ここまで来ると、

入力が何回間違ってもアプリは落ちない
エラーメッセージが具体的で分かりやすい
同じエラーハンドリングを何度でも再利用できる

という、かなり“アプリっぽい”状態になっています。


2日目で絶対に押さえてほしい本質

try / except を「部品」にしてしまう

今日いちばん大事なのは、

try / except
その場しのぎで書くのではなく、
「安全な入力関数」という形にして再利用する

という発想です。

どこで例外が起きうるかを見極める
その部分だけを try で囲う
「やり直しのループ」と組み合わせて、落ちない入力にする
同じパターンを関数にして、何度でも使えるようにする

ここまでできれば、
あなたの try / except はもう「初心者の防御」ではなく
「設計されたエラーハンドリング」 になっています。

3日目以降は、
これをファイル入出力やJSON保存アプリと組み合わせて、
「現実のアプリに耐えられるエラー処理」に育てていきます。

タイトルとURLをコピーしました