つくる:カテゴリ自動判定
このレッスンで作るもの — 第 4 章の総仕上げとして、品名からカテゴリを言い当てる
guess_categoryを作ります。おこづかい帳が入力を肩代わりしてくれるようになります。
つくる — カテゴリ自動判定
第 3 章までのおこづかい帳は、言われたことをそのまま整形するだけの道具でした。第 4 章で条件分岐を手に入れたので、ここで一歩進めます。品名を渡すだけでカテゴリを推測する 関数 guess_category です。
これがあると、記録するたびに「これは食費、これは娯楽」と人間が選ぶ手間がなくなります。
判定に使うキーワード
品名の中に決まった言葉が含まれているかで判定します。使うキーワードは下記のとおりです。
- 食費 —
りんご/パン/牛乳 - 日用品 —
ティッシュ/洗剤/歯ブラシ - 娯楽 —
映画/ゲーム/マンガ - 交通費 —
電車/バス/タクシー - その他 — 上のどれも含まれないとき
カテゴリはこの 5 種類だけです。おこづかい帳全体で使うカテゴリ名と一字一句そろえます。
判定の材料は、コードを書き始める前に文章で書き出しておきます。ここが曖昧なまま
ifを書き始めると、どこまで書けば完成なのか自分でも分からなくなります。
文字列に含まれるかを調べる
第 3 章の in 演算子は、文字列に対しても使えます。左に部分文字列、右に調べたい文字列を書くと、含まれていれば True になります。
"りんご" in "りんご3個" # True
"りんご" in "みかん" # Falseつまり "りんご" in name と書けば、品名が りんご そのものでも りんご3個 でも True になります。完全一致の == より当てはまる範囲が広く、実際の入力に強くなります。
組み立てる
キーワードの候補は or でつなぎ、カテゴリごとに elif で分けます。
def guess_category(name):
if "りんご" in name or "パン" in name or "牛乳" in name:
return "食費"
elif "ティッシュ" in name or "洗剤" in name or "歯ブラシ" in name:
return "日用品"
elif "映画" in name or "ゲーム" in name or "マンガ" in name:
return "娯楽"
elif "電車" in name or "バス" in name or "タクシー" in name:
return "交通費"
return "その他"最後の return "その他" は elif の外側に置きます。どのカテゴリにも当てはまらなかったときに、ここへ落ちてきます。
動きを追ってみる
guess_category("映画のチケット") の流れは下記のとおりです。
- 食費の 3 つのキーワードはどれも含まれず
False - 日用品の 3 つも
False - 娯楽の
"映画" in nameがTrueになり、return "娯楽"で終わる
guess_category("ノート") なら 4 つの elif をすべてすり抜けて return "その他" に到達します。「当てはまらない道」を必ず用意しておくのが、この形の肝です。
どの分岐にも入らなかったときの行き先を先に決めておくと、
Noneが返る事故が起きません。分岐を書いたら最後の受け皿を確認する癖を付けます。
この仕組みの限界
部分一致には弱点があります。バスタオル は日用品ですが バス を含むので交通費と判定されます。キーワードの当て方を工夫するか、品名とカテゴリの対応表を持つかで改善できますが、対応表を扱うには第 7 章の辞書が必要です。
今の道具で作れる範囲の、いちばん実用的な形がこれです。限界を知ったうえで使うのと、知らずに使うのとでは大違いです。
よくある間違い
name in "りんご"と左右を逆に書く —inは左が探すもの、右が探される場所です。逆にすると意味が反転します。orのたびにinを書き忘れる —if "りんご" or "パン" in name:は"りんご"が常にTrue扱いになるため、すべて食費になります。orでつなぐのは条件そのものです。- 最後の受け皿を忘れる —
elifだけで終えると、どれにも当てはまらない品名でNoneが返ります。
やってみよう
関数 guess_category(name) を実装してください。上のキーワード表のとおりに判定し、食費 / 日用品 / 娯楽 / 交通費 / その他 のいずれかを返します。
キーワードは in で部分一致を見ます。書けたら りんご 洗剤 映画のチケット 電車代 ノート の 5 つを渡して、5 種類の答えがすべて出ることを確かめてみてください。
要件
- 関数名は guess_category で、引数は name の 1 つ
- name に りんご / パン / 牛乳 のいずれかが含まれるなら "食費" を return する
- name に ティッシュ / 洗剤 / 歯ブラシ のいずれかが含まれるなら "日用品" を return する
- name に 映画 / ゲーム / マンガ のいずれかが含まれるなら "娯楽" を return する
- name に 電車 / バス / タクシー のいずれかが含まれるなら "交通費" を return する
- 上のどれにも当てはまらないときは "その他" を return する
- 判定は == の完全一致ではなく in の部分一致で行う
入出力例
guess_category("りんご") → "食費"
guess_category("牛乳パック") → "食費"
guess_category("洗剤") → "日用品"
guess_category("歯ブラシ") → "日用品"
guess_category("映画のチケット") → "娯楽"
guess_category("電車代") → "交通費"
guess_category("タクシー代") → "交通費"
guess_category("ノート") → "その他"
guess_category("") → "その他"