結論から言うと、TypeError は「型の使い方が合わない」とき、ValueError は「型は合っているが値の中身が合わない」ときに使います。
Pythonのエラーを読んでいると、TypeError と ValueError は何度も出てきます。
どちらも入力値に関係することが多いため、最初は似て見えるかもしれません。
この記事では、2つの違いを実務で判断しやすい形で整理します。
この記事でわかること
完成コード
完成コードは次の通りです。
def normalize_discount_rate(rate: int | float) -> float:
if not isinstance(rate, int | float):
raise TypeError("割引率は数値で指定してください")
if rate < 0 or rate > 100:
raise ValueError("割引率は0から100の範囲で指定してください")
return rate / 100
sample_rates = [10, 25.5, "30", -5, 120]
for rate in sample_rates:
try:
normalized_rate = normalize_discount_rate(rate)
except TypeError as error:
print(f"{rate!r}: 型を確認してください: {error}")
except ValueError as error:
print(f"{rate!r}: 値を確認してください: {error}")
else:
print(f"{rate!r}: {normalized_rate:.3f}")コードのポイント
このコードでは、割引率を受け取り、計算に使いやすい小数へ変換しています。
- 文字列のような数値ではない型なら
TypeErrorを出しています - 数値ではあるものの範囲外なら
ValueErrorを出しています except TypeErrorとexcept ValueErrorを分けて、確認する場所を変えています- 正しい値だけを
0.1のような小数に変換しています
TypeError と ValueError を分けると、エラーを見たときに「型を直すのか」「値の中身を直すのか」を判断しやすくなります。
コードを順番に説明します
主要な処理を分けて説明します。
1. 型そのものが合っているか確認します
if not isinstance(rate, int | float):
raise TypeError("割引率は数値で指定してください")この部分では、rate が整数または小数かどうかを確認しています。"30" のような文字列は、人間には数値に見えるかもしれませんが、Pythonでは文字列です。
関数が数値を前提にしているなら、文字列が渡された時点で型の使い方が合っていません。
このような場合は TypeError と考えると自然です。
2. 値の中身が条件に合っているか確認します
if rate < 0 or rate > 100:
raise ValueError("割引率は0から100の範囲で指定してください")この部分では、割引率が0から100の範囲に入っているかを確認しています。-5 や 120 は数値なので、型は合っています。
しかし、割引率として扱うには値の中身が不正です。
このように、型は合っているけれど業務ルールや関数の条件に合わない場合は ValueError が向いています。
3. 例外ごとに対応を分けます
except TypeError as error:
print(f"{rate!r}: 型を確認してください: {error}")
except ValueError as error:
print(f"{rate!r}: 値を確認してください: {error}")TypeError と ValueError を分けて受け止めると、利用者に伝える内容を変えられます。
型が違うなら、入力元や変換処理を確認します。
値が範囲外なら、入力値そのものや業務ルールを確認します。
実務では、CSVやフォームから受け取った値は文字列になりやすいです。
そのため、どの段階で文字列を数値に変換するかも、エラーの読みやすさに関係します。
実務で使うときのポイント
自分で例外を選ぶときは、次の順番で考えると整理しやすくなります。
- そもそも渡された型が違うなら
TypeError - 型は合っているが値の範囲や形式が違うなら
ValueError - 辞書のキーがないなら
KeyError - リストの位置が範囲外なら
IndexError
ただし、すべての関数で厳密な型チェックを書く必要はありません。
小さなスクリプトでは、Pythonが自然に出すエラーで十分な場合もあります。
一方で、共通関数や他の人が使う関数では、入り口で分かりやすい例外を出す価値があります。
エラーの原因が関数の中で深く進んでから出るより、最初に止まるほうが調査しやすいためです。
第4章の 4-4 で扱った raise と合わせて使うと、関数が受け付ける値の条件をコード上で明確にできます。
次の 4-6 では、実際のエラーメッセージをどの順番で読むかを整理します。