一覧PG-04-1 · 条件分岐

条件分岐と境界値

入場料金の年齢区分を題材に、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

1
def announce(age): if age < 13: print("child") print("checked")
2
announce(12); announce(13)
child
checked
checked
3
def fee(age): if age < 13: return 0 else: return 1000
4
[(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)]
5
def fee(age): if age >= 13: return 500 elif age >= 18: return 1000 else: return 0
6
[(age, fee(age)) for age in (12, 13, 17, 18, 19)]
[(12, 0), (13, 500), (17, 500), (18, 500), (19, 500)]
7
def fee(age): if age >= 18: return 1000 elif age >= 13: return 500 else: return 0
8
[(age, fee(age)) for age in (12, 13, 17, 18, 19)]
[(12, 0), (13, 500), (17, 500), (18, 1000), (19, 1000)]
9
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 

演習完了