try-exceptで備える

このレッスンで作るもの — 変換に失敗しても止まらない safe_int を作り、おかしな入力でも落ちないおこづかい帳にします。

try-except で備える

第 2 章で int("1200") を学びました。文字列を数値に変えるあの関数です。ただし、変換できる文字列にしか使えません。

int("120") # 120 になる int("abc") # ValueError で止まる

int("abc") を実行すると、ValueError という例外が起きてプログラムがそこで止まります。メッセージは invalid literal for int with base 10 と出ます。「10 進数として読めない文字だ」という意味です。

おこづかい帳では、金額の欄に打ち間違いが入ることがあります。全角で 120 と打ってしまう、うっかり 120円 と単位まで打ってしまう、空欄のまま送ってしまう。どれも int では読めません。

入力を扱うプログラムは、正しい入力より 正しくない入力のほうが多い くらいの気持ちで書きます。落ちないことが最低条件です。

例外は止めるのではなく受け止める

例外が起きても止まらないようにする構文が tryexcept です。

try: number = int(value) except ValueError: number = 0

try の中に「失敗するかもしれない処理」を書きます。もし例外が起きたら、その時点で try のブロックを抜け、except のブロックに移ります。例外が起きなければ except は素通りされます。

上のコードは「変換できたらその数値、できなかったら 0」という意味になります。except ValueError と種類を書いているので、受け止めるのは ValueError だけです。

try の中に return を書いてしまっても構いません。むしろそのほうが短く書けます。

def safe_int(value): try: return int(value) except ValueError: return 0

変換が成功すれば 1 つ目の return で関数が終わります。失敗したときだけ except に落ちて 0 を返します。

diagram (will load when visible)

int が通るもの、通らないもの

int は意外と寛容な部分もあります。前後の空白は無視してくれるので、int(" 80 ")80 になります。マイナス記号も読めるので int("-50")-50 です。

一方で、小数点の入った "12.5"ValueError になります。文字列からの変換では小数を経由してくれません。空文字 "" も読めません。

渡す値結果
"120"120
" 80 "80
"abc"ValueError
""ValueError
"12.5"ValueError

すでに int である値を渡した場合は、そのまま同じ数値が返ります。int(250)250 です。無駄にはなりますが害もないので、判定を書かずに全部 safe_int に通してしまうのが楽です。

どんな値が来ても数値が返る関数を 1 つ用意しておくと、呼び出す側から場合分けが消えます。安全な入口を 1 か所にまとめる、という考え方です。

よくある間違い

  1. except の範囲を広げすぎるexcept: とだけ書くと、あらゆる例外を飲み込んでしまいます。本当のバグまで隠れて原因が追えなくなるので、受け止める種類は必ず書きます。
  2. try の範囲を広げすぎるtry のブロックに関係ない処理まで入れると、どこで失敗したのか分からなくなります。危ない 1 行だけを囲むのが基本です。
  3. except で何もしないexcept ValueError: pass と書くと、失敗を無視して先に進みます。今回は 0 を返すという後始末があるので、pass は使いません。

if で事前に判定しようとして、条件が延々と増えていくのもよくある回り道です。「やってみて失敗したら対処する」ほうが Python では素直です。

やってみよう

関数 safe_int(value) を実装してください。valueint に変換して返します。変換できないときは ValueError を受け止めて 0 を返します。

try の中に return int(value) を書き、except ValueError の中に return 0 を書く形が最短です。"120"120"abc"0、空文字 ""0 になれば正解です。すでに数値の 250 を渡しても 250 が返ることを確かめてみてください。

要件

  1. 関数名は safe_int で、引数は value の 1 つ
  2. try の中で int による変換を試す
  3. except ValueError で受け止め、0 を返す
  4. except の種類を省略して全部を飲み込む書き方はしない
  5. 変換に成功したときはその数値をそのまま返す

入出力例

safe_int("120")120 safe_int("abc")0 safe_int("")0 safe_int("0")0 safe_int(" 80 ")80 safe_int(250)250 safe_int("12.5")0

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.py
main.py
学習モード

メモ

try-exceptで備える

⌘S で保存