try-exceptで備える
金額の欄に 120円 と打たれると、そこで止まる
int("120") は 120 になります。ただし、変換できる文字列にしか使えません。
Python
print(int("abc"))ValueError が起きてプログラムが止まります。メッセージは invalid literal for int with base 10 で、10 進数として読めない文字だ、という意味です。
おこづかい帳の金額欄には、いろいろなものが入ってきます。全角で 120 と打つ、単位まで付けて 120円 と打つ、空欄のまま送る。どれも int では読めません。入力を扱うプログラムは、正しくない入力のほうが多いくらいの気持ちで書きます。落ちないことが最低条件です。
int が意外と寛容な部分も知っておきます。前後の空白は無視されるので int(" 80 ") は 80 になり、int("-50") も読めます。一方で、小数点の入った "12.5" と空文字 "" は読めません。すでに int の値を渡した場合はそのまま同じ数値が返るので、害はありません。
止めるのではなく、受け止める
例外が起きても止まらないようにする構文が try と except です。
Python
try:
number = int(text)
except ValueError:
print("数字として読めませんでした")try の中に「失敗するかもしれない処理」を書きます。例外が起きたらその場で try を抜け、except のブロックへ移ります。何事もなければ except は素通りされます。
try の中に return を書いても構いません。むしろ関数の中では、成功したらそのまま返し、失敗したときだけ except で別の値を返す形が短く書けます。
どんな値が来ても数値が返る関数を 1 つ用意しておくと、呼び出す側から場合分けが消えます。安全な入口を 1 か所にまとめる、という考え方です。if で事前に判定しようとして条件が延々と増えていくより、やってみて失敗したら対処するほうが Python では素直です。
except: とだけ書かない
except のうしろに種類を書かず except: とだけ書くと、あらゆる例外を飲み込みます。楽に見えますが、本当のバグまで一緒に隠れて原因が追えなくなります。受け止める種類は必ず書きます。
try の範囲も広げすぎないようにします。関係のない処理まで中に入れると、どこで失敗したのかが分からなくなります。危ない処理だけを囲むのが基本です。
except ValueError: pass のように、受け止めておいて何もしないのも避けます。例外処理は、失敗を無かったことにする道具ではありません。失敗したときにどう振る舞うかを決める道具です。
やってみよう
関数 safe_int(value) を実装してください。value を int に変換して返し、変換できないときは ValueError を受け止めて 0 を返します。
受け止める種類は ValueError と明示してください。"120" は 120、"abc" は 0、空文字 "" も 0 になれば正解です。すでに数値の 250 を渡しても 250 が返ることを確かめてみてください。
要件
- 関数名は safe_int で、引数は value の 1 つ
- try の中で int による変換を試す
- except ValueError で受け止め、0 を返す
- except の種類を省略して全部を飲み込む書き方はしない
- 変換に成功したときはその数値をそのまま返す