# 条件分岐

## 条件分岐とは
```{figure} ./figs/branching.svg
:name: branching
条件分岐とは
```

プログラムを利用する現場では、ある特定条件を元にそれ満足する場合のコードと、満足しない場合のコードを分けて記述したい状況が良くある。**{index}`条件分岐<じょうけんぶんき-条件分岐>`（{index}`conditional statement`, {index}`if-statement`）** と呼ばれ、**{index}`判定式<はんていしき-判定式>`・{index}`条件式<じょうけんしき-条件式>`（{index}`test`, {index}`condition`）** と **それぞれの場合のコード（ブロック; block）** とを分けて記述することになる。次に示す具体例を参照しながら条件分岐を学んでみよう。

---
## コード例
```python
score = 30
if score >= 90:
    eval = 'A'
    print('{}点とはなかなか高評価だね！'.format(score))
    print('その調子で頑張ろう！')
else:
    print('分からないところは自分から相談しよう！')

print('条件分岐終了')
```

このコード例は、変数scoreに保存された点数が90点以上ならば、変数evalに 'A' を保存し、2つのprint文を実行する。もしくは、点数が90点未満ならば1つのprint文を実行する。また、分岐を抜けた後は共通して「条件分岐終了」と出力する。というコードである。

ここで条件分岐における「条件式」は ``score >= 90`` と記述している箇所である。また、条件式の後ろにコロン(colon) ``:`` を記述することを忘れないようにしよう。このように条件分岐は ``if 条件式:`` として記述し始め、妙な空白で揃えられた命令群と ``else:``、そしてもう一度妙な空白で揃えられた命令群という形式で記述する。ただしelse以下は不要ならば省略しても良い。

条件式は、[第2回の用語集2](./week2.html#operator-type-int-float-str-bool-variable-comparison)や[用語集3](./week2.html#comment-boolean)で述べた比較演算子を用いて表現する。例えば、変数 eval に保存された内容が文字列リテラル 'B' と等しいかどうか判断したい場合には次のように書く。
```python
eval == 'B'
```
この結果、等しいならば True となり、等しくないならば False という判定結果が得られる。

条件式の結果は必ず bool 型リテラル（True, False）である。逆に言えば、評価結果がbool型とならないコードを記述すると、エラーになる（試してみよう）。条件式の結果が True のときに実行すべきコードが、少しスペースを加えて、同じ幅で揃えて記述した3行のコードである。このまとまりを **{index}`ブロック<ぶろっく-ブロック>`({index}`block`)** と呼ぶ。ブロックを指定するためには **(a)スペースを挿入することと、(b)複数コードをまとめたい場合には同一幅で揃えて書く** 必要がある。例えば以下のようなコードは True ブロックである。
```python
# 例1。Trueブロックのみで、ブロックに1行で終わる例。
if True:
    print('test')

# 例2。Trueブロックのみで、ブロックに2行ある例。
if True:
    print('test')
    print('test2')
```
上記に対し、以下のコードはブロックとして不適切であり、エラーになる（確認してみよう）。
```python
# 例3。Trueブロックのみで、スペースが揃っていない例。
if True:
  print('test')
    print('test2')
```
例3は、1つ目のprint文と2つ目のprint文の冒頭スペースが揃っておらず、異なる2つのブロックを記述していることになる。ところが、ブロックを書くためには条件分岐等特別な状況でしか書くことが許されていない。このため、例3はエラーとなる。

```{note}
例3の場合には「{index}`IndentationError`: unexpected indent」と返される。文字通り「期待した通りのインデントではない」というエラーであり、文法上このような書き方は許可されていない。
```

`````{admonition} 検討
変数x, yには任意の数値が保存されているとしよう。このとき、条件分岐を用いて大きい変数を返す関数を実装してみよう。関数名を max とする。
````{dropdown} 回答例
```python
def max(x, y):
    if x < y:
        return y
    else:
        return x

#動作確認
print(max(3, 5))
print(max(13, 5))
```
````
`````

---
## コードからブロックを把握する1
```{figure} ./figs/if-example1.svg
:name: if-example1
if文の例1
```

上記のコードは先程説明したコードと全く同じである。「ブロックを示すために記述する冒頭スペース」のことを **{index}`インデント<いんでんと-インデント>`({index}`indent`)** と呼ぶ。基本的には **スペース4つ** を1単位として加えると覚えておこう。このようにブロックを記述することを「インデントを入れる」とか「インデントを揃える」というように呼ぶ。

```{note}
注意してほしいのは、コードを見ただけで以下の2点を判断できることが求められていることだ。

- **コードを見ただけでどこがブロックになっているのかが分かる**。
- **そのブロックはどの条件に関する True ブロックなのか、Falseブロックなのかが分かる**。
```

改めてコードだけを書くと次のようになる。
```python
score = 30
if score >= 90:
    eval = 'A'
    print('{}点とはなかなか高評価だね！'.format(score))
    print('その調子で頑張ろう！')
else:
    print('分からないところは自分から相談しよう！')

print('条件分岐終了')
```
このコードを見て、どこが条件式で、どこがその条件式に対する True ブロックか分かるだろうか。どこがFalseブロックか分かるだろうか。なお、Falseブロックは必ずしも記述する必要はなく、Trueブロックのみのコードであることもある。更に、条件分岐は必ずしも1回で終わるとは限らない。次の例を見てみよう。

```python
score = 80
eval = 'F'
if score >= 60:
    if score < 70:
        eval = 'D'
print(eval)
```

上記の例は、
- 1つ目のif文のTrueブロック（1行のみ）の中に、さらにif文がある。
- 2つ目のif文のTrueブロック（1行のみ）の中に、変数evalを設定する記述がある。

つまり、2つのブロックがそれぞれのif文におけるTrueブロックに対応している。ブロックの範囲はインデントが揃っているかどうかで判断される。

このように、**どこからどこまでが1つのブロックなのか。そのブロックはどこに対応しているのか、を読み取れるようになろう**。また、コードを書く際にはいきなり書くのではなく、[冒頭図](#id2)のようにコード全体の分岐の流れをイメージしやすくなるように紙の上で図を書いて、流れを整理してみよう。この流れを検討する部分こそが、第1回授業資料における「理解・整理・翻訳」の前2つのステップに相当する。いきなり翻訳するのは慣れてきてからで十分だ。

---
## コードからブロックを把握する2
```python
score = 80
if score >= 90:
  	eval = 'A'
  	print('{}点とはなかなか高評価だね！'.format(score))
  	print('その調子で頑張ろう！')
elif score >= 80:
  	eval = 'B'
elif score >= 70:
  	eval = 'C'
elif score >= 60:
  	eval = 'D'
else:
  	print('分からないところは自分から相談しよう！')
```

条件式を書く際、
- 条件1：90点以上ならば処理1を。
- 条件2：そうではなく、80点以上ならば処理2を。

この条件2のように「条件1でFalseになった上で追加したい条件」を書きたい場合には、 **{index}`elif文`** を使う。elif は else ifの略であり、その前の条件式には合致しなかったことを踏まえて判断される。

最後の ``else文`` は、そこに到達するまでの全ての条件式に対しFalseとなったときだけ実行されることになる。今回のコード例では、変数scoreの中身が60未満のときだけelseブロックが実行される。

````{note}
数値に対する比較演算子を用いる場合には「以上」と「より大きい」とで意味（演算子）が異なる点に注意しよう。下記コードの1つ目のprint結果は True となり、2つ目は False となる。
```python
score = 10
print(score <= 10)
print(score < 10)
```
````

```{note}
条件式は比較演算子を ``0 <= score <= 20`` のように複数演算子を列挙して書くことも可能である。また ``0 <= score and score <=20`` のように論理積として書くこともできる。

``and（論理積）`` は両辺のブール値がTrueであるときにTrue、それ以外のときにはFalseとなる演算子である。``or (論理和)`` は両辺のブール値のうちどちらか片方（もしくは両方）がTrueであるときにTrue、それ以外（両方ともFalse）のときにはFalseとなる演算子である。

このように説明を書くと分かりにくいかもしれないので例を示そう。あるゲームのステージクリア条件が「100秒以内にすべての敵を殲滅」のように、用意された複数条件全てを満足したときだけクリアとみなしたい時に用いるのが論理積だ。これに対して「100秒生存するか、もしくはすべての敵を殲滅」のように用意された条件いずれかを満足できればクリアとみなしたい時に用いるのが論理和だ。
```

---
## 関数定義との組み合わせ
関数定義における関数ブロックや、条件分岐におけるTrueブロック・Falseブロックはいずれもインデントによりブロックを明確にする必要がある。演習を通してこの練習をしてみよう。

```python
value = 5
if value % 3 == 0:
    result = 'アホ'
else:
    result = value
```

上記コードは[世界のナベアツ](https://ja.wikipedia.org/wiki/桂三度#世界のナベアツ)をイメージし、与えられた数値が3の倍数の時にアホを生成し、それ以外のときは数字そのものを生成するコードである。このコードを参考に「与えられた数値に基づき、3の倍数の時に 'アホ' と返し、それ以外のときには数字を返す関数」を実装してみよ。

`````{admonition} 検討
````{dropdown} 回答例
```python
# 例1
def play_nabeatsu(input_value):
    if input_value % 3 == 0:
        result = 'アホ'
    else:
        result = input_value
    return result

# 例2
def play_nabeatsu(value):
    if value % 3 == 0:
        return 'アホ'
    else:
        return value
```
````
`````

---
## 復習・予習
- 復習
  - 適宜過去資料及び教科書を参照しよう。
- 予習
  - 2.4 Iteration
  - （3章スキップ）
  - 4.1〜4.1.1 Function Definitions
