if、elif、elseで判断する
条件によって違う道を選ぶこと、Pythonでインデントが意味を持つ理由、そして条件の順番を誤ったときに起きる静かなバグを学びます。
どうやって学びますか?
解決する問題
前の章では、問いを立てることを学びました。age >= 18は真でしょうか、それとも偽でしょうか? しかし答えが分かっても、プログラムはそれを使って何もしませんでした。TrueかFalseを表示しただけです。
今度は、その答えにもとづいて行動する番です。条件が成り立つときの道と、成り立たないときの道を用意します。ここから先で、コードは手順の並びではなく、判断するものになります。
ここで、Pythonは多くの他のプログラミング言語と違います。どの行が条件の中にあり、どの行が外にあるかは、空白によって決まります。波かっこ{}はありません。最初は不思議に感じるかもしれませんが、すぐに気に入るはずです。整理されて見えるコードは、実際に整理されているからです。
この章を終える頃には
ifで条件付きにコードを実行できるelseで別の道を用意でき、elifで複数の道を用意できる- 正しくインデントでき、
IndentationErrorを読んで直せる - 条件の順番が大切な理由を説明できる。ここが最大の落とし穴です
- 条件の中に別の条件を入れ子にでき、それを避けるべきときが分かる
前提条件: True and False — 問いを立てることを学ぶ。
最も単純な形
age = 22
if age >= 18:
print("You may enter")
print("Program finished")You may enter
Program finishedこの形は3つの部分でできています:
ifという語と、その後に続く条件- 条件の末尾にあるコロン
:— これを書き忘れるのが最もよくあるミスです - そのあとに続く行を4つの空白でインデントします — インデントされた行だけが、その条件の対象になります
ageが15だったとしたら、最初のprintは実行されません。しかし最後のprintは、条件の外にあるので実行されます。
インデントが意味を持つ
これら2つのプログラムは、ほぼ同じ文字でできていますが、動きはまったく違います:
score = 30
if score >= 50:
print("Passed")
print("Certificate issued")これを実行すると、何も表示されません。2行とも条件の中にあり、条件が偽だからです。
score = 30
if score >= 50:
print("Passed")
print("Certificate issued")Certificate issued2つ目のprintは条件の外に出たので、必ず実行されます。その結果、不合格の人に修了証が発行されてしまいました。1行のインデントを間違えるだけで、業務のルールが壊れてしまいます。 しかもPythonはエラーを出しません。どちらのバージョンも正しいコードだからです。
空白は4つ、タブではありません。 Pythonはどちらも受け付けますが、1つのファイルで混ぜるとTabErrorが起きます。タブとスペースは画面上では同じに見えるため、見つけるのに苦労します。第1章でインストールしたVS Codeでは、Pythonファイルの中でTabキーを押すと4つの空白が入ります。これが既定の設定であり、4つの空白はPythonの公式な慣習でもあります。else — もう1つの道
age = 15
if age >= 18:
print("You may enter")
else:
print("Sorry, adults only")Sorry, adults onlyelseには条件がありません。その条件はすでに示されているからです。「上のどれも真でなければ」という意味です。ifとelseのうち、ちょうど1つだけが実行されます。両方が実行されることも、どちらも実行されないこともありません。
elif — 複数の道
marks = 72
if marks >= 80:
grade = "A"
elif marks >= 70:
grade = "B"
elif marks >= 60:
grade = "C"
elif marks >= 40:
grade = "D"
else:
grade = "F"
print(f"Marks {marks} gives grade {grade}")Marks 72 gives grade Belifは「そうでなければ、もし」という意味です。Pythonは連なりを上から順にたどり、最初に真だと分かった条件のブロックを実行し、そのあと連なり全体を抜けます。 残りの条件はテストすらしません。
marks = 72のとき: 72 >= 80は偽、72 >= 70は真なのでgrade = "B"になり、そこで終わります。72 >= 60と72 >= 40も真ですが、それらは一度も見られません。
そして最大の落とし穴
elifは最初に真になった条件で止まるため、順番を間違えると、エラーは出ないのに答えだけが間違っているプログラムになります:
marks = 95
if marks >= 40:
grade = "Pass"
elif marks >= 80:
grade = "Excellent"
else:
grade = "Fail"
print(grade)Pass95点なのにExcellentになりません。95 >= 40がすぐに真になり、Pythonはそこで止まったからです。2つ目の条件は、まったくテストされませんでした。
覚えておくべきルール: 最も厳しく、最も具体的な条件を先に書き、最もゆるい条件を最後に書きます。 数値の区分を扱うときは、上の成績の例のように、大きい方から順に下っていきます。
このバグは非常に静かなので、見つける唯一の方法は実際に確かめることです。だから習慣にしてください。条件の連なりを書いたら、それぞれの分岐に当たる値を1つずつ与えて、一度実行してみましょう。上の成績のコードは、95、72、65、45、20で5つの異なる答えを出すはずです。もし2つの答えが同じなら、順番が間違っています。
条件の中の条件
is_logged_in = True
is_admin = False
if is_logged_in:
if is_admin:
print("Welcome, admin")
else:
print("Welcome, user")
else:
print("Please log in")Welcome, user内側のifは外側のifの下にあるので4つの空白でインデントされ、その中のprintの行は8つの空白でインデントされています。これでも動きますが、階層が増えるほど読みにくくなります。andを使うほうが、同じことを明確に表せることがよくあります:
is_logged_in = True
is_admin = False
if is_logged_in and is_admin:
print("Welcome, admin")
elif is_logged_in:
print("Welcome, user")
else:
print("Please log in")Welcome, userどちらのほうが良いかは、どちらが読みやすいかによります。3階層より深くなったと感じたら、立ち止まって考え直しましょう。 条件の組み立て方を変えられることが、ほとんどの場合のサインです。
入力の検証
前の章で残した問題(相手が何も入力しなかったり、単語を入力したりしたときにどうするか)を解決する道具が、これで揃いました:
raw = input("Your age: ").strip()
if raw == "":
print("You did not type anything")
elif raw.isdigit():
age = int(raw)
if age >= 18:
print(f"Age {age}: you may enter")
else:
print(f"Age {age}: adults only")
else:
print(f"'{raw}' is not a whole number")Your age: twenty
'twenty' is not a whole numberisdigit()は新しいメソッドです。テキストのすべての文字が数字かどうかを教えてくれます。何かをint()に渡す前に確認する簡単な方法で、これによりValueErrorは起きなくなります。(isdigit()は負の数や小数を受け付けません。それらにはtryが必要ですが、それは後の章で学びます。)
完成例
fare.py:
# Work out a ticket fare from age and day of week
age = int(input("Passenger age : "))
day = input("Day of week : ").strip().lower()
base_fare = 120.0
# Most specific rule first, loosest last
if age < 5:
fare = 0.0
category = "Infant"
elif age < 18:
fare = base_fare * 0.5
category = "Child"
elif age >= 60:
fare = base_fare * 0.7
category = "Senior"
else:
fare = base_fare
category = "Adult"
is_weekend = day == "saturday" or day == "sunday"
if is_weekend:
fare = fare * 1.2
print()
print(f"Category : {category}")
print(f"Weekend : {is_weekend}")
print(f"Fare : {fare:.2f}")Passenger age : 65
Day of week : Sunday
Category : Senior
Weekend : True
Fare : 100.80ここでは2つの設計上の判断に注目してください。1つ目は、年齢の条件をelifでつないでいることです。乗客はちょうど1つの区分に入るからです。2つ目は、週末の条件が独立したifになっていることです。これは独立した問いだからです。年齢にかかわらず、週末の割増料金はその上に加算されます。何をelifにし、何を独立したifにするかを決めることこそが、条件を書くうえでの本当の仕事です。
うまくいかないとき
SyntaxError: expected ':' if、elif、またはelseの行の末尾にあるコロンが抜けています。
IndentationError: expected an indented block after 'if' statement ifの次の行がインデントされていません。条件の中には、少なくとも1行が必要です。
IndentationError: unexpected indent 理由もなくインデントされている行があります。その行がどのブロックに属するべきかを考えてください。
TabError: inconsistent use of tabs and spaces in indentation 1つのファイルの中でタブとスペースが混ざっています。エディタで「インデントをスペースに変換」を実行してください。
SyntaxError — 単独で書かれたelifやelse elifとelseは必ずifに属し、そのifと同じ深さにインデントされていなければなりません。
TypeError: '>=' not supported between instances of 'str' and 'int' input()の変換を忘れています。int(input(...))と書いてください。
条件は正しく見えるのに、違う道に進んでしまう 順番を確認してください。ゆるい条件が先にあると、厳しい条件は一度もテストされません。それぞれの分岐に当たる値を1つずつ与えて、一度実行してみてください。
ステップ 4 / 6 — 予想する
理解度をチェック
85点のとき、このプログラムは何を表示しますか?
marks = 85
if marks >= 40:
print("Pass")
elif marks >= 80:
print("Excellent")
else:
print("Fail")- AExcellent Pass
- BPass
- CPass Excellent
- DExcellent
このプログラムは何を表示しますか?
score = 30
if score >= 50:
print("Passed")
print("Done")- APassed Done
- BDone
- C何も表示されない
- DPassed
相手が25と入力しても、TypeErrorで止まってしまいます。原因は何で、どう直せばよいでしょうか?
age = input("Age: ")
if age >= 18:
print("Adult")
else:
print("Minor")- A`input()`が返すのはテキストで、テキストは数値と比べられません — `age = int(input("Age: "))`とする必要があります
- B`else`の前には`elif`が必要である
- C`>=`は`if`の条件では使えません。`>`にする必要があります
- D`age`は予約語なので、比較が失敗した
回答にはアカウントが必要です
ログインして答えを確認
問題は上にあります。頭の中で答えを考えることがいちばん大切です。ログインすると、正解・解説・3 段階のヒントを確認できます。
やってみよう
bmi.pyという名前のファイルを書いてください。身長をメートル、体重をキログラムで受け取り、BMIを計算して、そのカテゴリを表示します。
計算式: bmi = weight / (height * height)
カテゴリは次のとおりです:
- 18.5未満 — Underweight
- 18.5以上25未満 — Normal
- 25以上30未満 — Overweight
- 30以上 — Obese
境界の書き方は、わざと「未満」(<)と「以上」(>=)にしてあります。「18.5から24.9」と書くと、途中に隙間ができてしまいます。たとえばBMIが24.95だと、どのカテゴリにも入らなくなります。<と>=を使えば、どの数もちょうど1つのカテゴリに入ります。
次の4つの条件を満たしてください:
- BMIを小数点以下1桁で表示する
- 4つのカテゴリすべてが本当に動くように、条件の順番を決める
- 身長が
0なら、割る前に止まってメッセージを表示する。そうしないとZeroDivisionErrorになります - 4つのカテゴリをそれぞれ代表する4つの値で実行し、さらに境界値ちょうどの値でも実行する。BMIがちょうど25のとき、どのカテゴリに入るでしょうか?(Overweightになるはずです。)
4つ目の条件がいちばん重要です。境界ちょうどの値こそ、条件の順番の間違いが表に出てくる場所だからです。
このミッションにはまだ続きがあります
上で読んだ内容がミッションのすべてで、削られた部分はありません。Pro では次の内容が追加されます:
- 内部で実際に何が起きているか — Python がこれをどう実行するのか
- 演習の完全な解答と、ステップごとの解説
- さらに難しい追加演習
- このテーマでよく聞かれる面接の質問と模範解答