条件分岐と境界値
入場料金の年齢区分を題材に、13歳・18歳の境界と条件の順番を変えます。会員・支払・招待の条件も一覧で確かめ、意図した人がどの枝へ進むか確認します。
説明
ifは条件が真のときに本体を実行し、elseは偽のときの処理を指定します。elifをつないだ場合は、上から調べて最初に真となった枝だけを実行します。
入場料金の年齢区分を題材に、13歳・18歳の境界と条件の順番を変えます。会員・支払・招待の条件も一覧で確かめ、意図した人がどの枝へ進むか確認します。
1ifだけの場合と共通処理
非負の整数の年齢を扱います。まず13歳未満だけ案内を出す関数を作ります。最後のcheckedはifの外です。
def announce(age):年齢を受け取る関数
if age < 13:13歳未満
print("child")条件が真のときだけ
print("checked")分岐後の共通処理ifの字下げ内は条件が真のときだけ、最後の行は条件に関係なく実行します。elseを書かなくても、偽ならifの本体を飛ばして続きへ進みます。
2境界の両側で呼び出す
12歳と13歳で、表示される行を比較します。
announce(12)境界の直前; announce(13)境界そのもの12歳ではchildとchecked、13歳ではcheckedだけです。<13は13を含みません。二回の呼出しで、共通処理は二回とも実行されています。
3elseで二つの値を返す
13歳未満は0円、それ以外は1000円とする関数を定義します。
def fee(age):料金を返す関数
if age < 13:子供の条件
return 0子供料金
else:条件が偽の場合
return 1000通常料金一つのif/elseでは、どちらか一方のreturnへ進みます。各枝でreturnすると関数が終了するので、その呼出しで両方の料金を返すことはありません。
4等号を含むか確認
境界付近の料金と、<13と<=13の判定を並べます。
[(age, fee(age), age < 13, age <= 13年齢・料金・二つの条件) for age in (12, 13, 14)境界の前後を確認]13歳だけが<と<=で変わります。年齢区分を文章で決めた後、等号がどちらの区分へ入るかを確かめます。いまのfeeは13歳から1000円です。
5広い条件を先に書いた場合
13〜17歳を500円、18歳以上を1000円に分けたいとします。まずこの条件順で定義します。
def fee(age):
if age >= 13:広い条件を先に判定
return 500先に選ばれる値
elif age >= 18:先行条件に含まれる狭い条件
return 1000到達できない値
else:13歳未満
return 0子供料金age>=18なら必ずage>=13も真です。先に500円を返して終了するため、この順では1000円の枝に到達できません。
6到達しない枝を入力で確かめる
13歳、17歳、18歳、19歳を同じ関数へ渡します。
[(age, fee(age)) for age in (12, 13, 17, 18, 19)]区分の前後をまとめて実行18歳と19歳も500円になりました。elifの条件が単独なら真でも、先の枝で処理が終わればそこまで評価されません。
7狭い条件を先にする
18歳以上を先に判定し、それに該当しない13歳以上を500円にします。
def fee(age):
if age >= 18:18歳以上を先に判定
return 1000通常料金
elif age >= 13:残った13歳以上
return 50013〜17歳の料金
else:残る範囲
return 013歳未満の料金二つ目へ進んだ時点でage<18が確定しています。二つ目の実質的な範囲は13以上18未満となり、区分の重複を避けられます。
8修正後も同じ境界で確認
同じ入力列を再実行します。
[(age, fee(age)) for age in (12, 13, 17, 18, 19)]修正前と同じ境界値0、500、500、1000、1000となりました。条件を直した後も同じ境界値を使うと、どの区分が変わったか比較できます。
9複合条件の括弧と全組合せ
入場条件を「会員で、支払済みか招待あり」とします。括弧がない場合との違いを全8通りで表示します。
import itertools; rows = list(itertools.product((False, True), repeat=3))三条件の全組合せ; print("member paid invite | intended without_parentheses")条件と結果の見出し; print("\n".join(f"{m!s:5} {p!s:5} {i!s:5} | {m and (p or i)会員で支払または招待!s:5} {m and p or i括弧なしの別条件!s:5}" for m,p,i in rows))andはorより強く結び付くので、括弧なしは(member and paid) or inviteです。招待ありなら非会員も通ります。意図する条件では会員であることが必須です。否定を使う場合も、not(member and paid)とnot member and paidは別の条件になります。
まとめ
境界の等号と、先に真になる条件を確認します。
複合条件は括弧を含めて要件へ対応付け、全組合せを調べます。
操作履歴と解説を振り返れます。
Python 3
def announce(age):
if age < 13:
print("child")
print("checked")announce(12); announce(13)child checked checked
def fee(age):
if age < 13:
return 0
else:
return 1000[(age, fee(age), age < 13, age <= 13) for age in (12, 13, 14)][(12, 0, True, True), (13, 1000, False, True), (14, 1000, False, False)]
def fee(age):
if age >= 13:
return 500
elif age >= 18:
return 1000
else:
return 0[(age, fee(age)) for age in (12, 13, 17, 18, 19)][(12, 0), (13, 500), (17, 500), (18, 500), (19, 500)]
def fee(age):
if age >= 18:
return 1000
elif age >= 13:
return 500
else:
return 0[(age, fee(age)) for age in (12, 13, 17, 18, 19)][(12, 0), (13, 500), (17, 500), (18, 1000), (19, 1000)]
import itertools; rows = list(itertools.product((False, True), repeat=3)); print("member paid invite | intended without_parentheses"); print("\n".join(f"{m!s:5} {p!s:5} {i!s:5} | {m and (p or i)!s:5} {m and p or i!s:5}" for m,p,i in rows))member paid invite | intended without_parentheses False False False | False False False False True | False True False True False | False False False True True | False True True False False | False False True False True | True True True True False | True True True True True | True True
演習完了