2-3. 条件分岐

制御構造のうち条件分岐について説明します。

参考:

if で始まり条件分岐を行う制御構造によって、条件に応じてプログラムの動作を変えることができます。

ここではまず「インデント」について説明し、そのあとで条件分岐について説明します。

インデントによる構文

条件分岐の前に、Pythonのインデント(行頭の空白、字下げ)について説明します。 Pythonのインデントは実行文をグループにまとめる機能を持ちます。

プログラム文はインデントレベル(深さ)の違いによって異なるグループとして扱われます。 細かく言えば、インデントレベルが進む(深くなる)とプログラム文はもとのグループの下に位置する 別のグループに属するものとして扱われます。 逆に、インデントレベルが戻る(浅くなる)までプログラム文は同じグループに属することになります。

具体例として、第1回で定義した関数 bmax() を使って説明します:

[1]:
def bmax(a,b):
    if a > b:
        return a
    else:
        return b

print('Hello World')
Hello World

この例では1行目の関数定義 def bmax(a,b): の後から第1レベルのインデントが開始され5行目まで続きます。 すなわち、5行目までは関数 bmax を記述するプログラム文のグループということです。

次に、3行目の一行のみの第2レベルのインデントの実行文は、 if文(if による条件分岐)の論理式 a > bTrue の場合にのみ実行されるグループに属します。 そして、4行目の else ではインデントが戻されています。 5行目から再び始まる第2レベルの実行文は2行目の論理式が False の場合に実行されるグループに属します。

最後に、7行目ではインデントが戻されており、これ以降は関数 bmax() の定義とは関係ないことがわかります。

Pythonではインデントとして半角スペース4つが広く利用されています。 本教材でもこの書式を利用します。 1-4 のコーディングスタイルのところで紹介したスタイルガイドのPEP8でも、 半角スペース4つが推奨されています。

Codeセルでは行の先頭でTabを入力すれば、自動的にこの書式のインデントが挿入されます。 また、インデントを戻すときはShift-Tabが便利です。 なお、Colaboratoryでは、Tabを入力すると半角スペース2つのインデントが挿入されます。

ifelse による条件分岐

これまで関数 bmax を例にとって説明しましたが、一般にif文では、 が真であれば if 直後のグループが、偽であれば else 直後のグループが、それぞれ実行されます。(真であった場合、else 直後のグループは実行されません。)

if 式:
    ここのグループは「式」が真のときにのみ実行される
else:
    ここのグループは「式」が偽のときにのみ実行される

また、else は省略することができます。省略した場合、「式」が真のときに if 直後のグループが実行されるのみになります。

if 式:
    ここのグループは「式」が真のときにのみ実行される
ここのグループは常に実行される

条件が複雑になってくると、if文の中にさらにif文を記述して、条件分岐を入れ子ネスト)にすることがあります。 この場合は、インデントはさらに深くなります。

そして、下の2つのプログラムの動作は明らかに異なることに注意が必要です。

if 式1:
    ここのグループは「式1」が真のときにのみ実行される
    if 式2:
        ここのグループは「式1」「式2」が共に真のときにのみ実行される
        if 式3:
            ここのグループは「式1」「式2」「式3」が全て真のときにのみ実行される
        ここのグループは「式1」と「式2」が共に真のときにのみ実行される
    ここのグループは「式1」が真のときにのみ実行される
ここのグループは常に実行される
if 式1:
    ここのグループは「式1」が真のときにのみ実行される
ここのグループは常に実行される
if 式2:
    ここのグループは「式2」が真のときにのみ実行される (「式1」には影響されない)
ここのグループは常に実行される
if 式3:
    ここのグループは「式3」が真のときにのみ実行される (「式1」「式2」には影響されない)
ここのグループは常に実行される

ifelifelse による条件分岐

ここまでで if ... else 文について紹介しましたが、複数の条件分岐を続けて書くことができる elif を紹介します。

たとえばテストの点数から評定(優、良、可、…)を計算したい場合など、「条件1のときは処理1、条件1に該当しなくても条件2であれば処理2、更にどちらでもない場合、条件3であれば処理3、…」という処理を考えます。 if ... else による文のみでこの処理を行う場合、次のようなプログラムになってしまいます:

if 式1:
    「式1」が真のときにのみ実行するグループ
else:
    if 式2:
        「式1」が偽 かつ「式2」が真のときにのみ実行するグループ
    else:
        if 式3:
            「式1」「式2」が偽 かつ「式3」が真のときにのみ実行するグループ
        else:
            ...

このような場合には、以下のように elif を使うとより簡潔にできます:

if 式1:
    ここのグループは「式1」が真のときにのみ実行される
elif 式2:
    ここのグループは「式1」が偽 かつ「式2」が真のときにのみ実行される
elif 式3:
    ここのグループは「式1」「式2」が偽 かつ「式3」が真のときにのみ実行される
else:
    ここのグループは「式1」「式2」「式3」がいずれも偽のときにのみ実行される

ifelifelse では、条件は上から順に評価され、式が真の場合、 直後の実行文グループのみが実行され終了します。 その他の場合、すなわち全ての条件が False のときは、else 以降のグループが実行されます。

なお、elif もしくは else 以降を省略することも可能です。

練習

関数 exception3(x,y,z) の引数は以下の条件を満たすとします。

  • xyz の値は整数です。

  • xyz のうち、2つの値は同じで、もう1つの値は他の2つの値とは異なるとします。

その異なる値を返すように、以下のセルの ... のところを書き換えて exception3(x,y,z) を定義してください。

[2]:
def exception3(x,y,z):
    ...

次のセルで動作を確認してください。

[3]:
print(exception3(1,2,2))
print(exception3(4,2,4))
print(exception3(9,3,9))
None
None
None

練習

関数 exception9(a) の引数は以下の条件を満たすとします。

  • 引数 a には、長さが9のリストが渡されます。

  • このリストの要素は整数ですが、1つの要素を除いて、残りは要素の値は全て同じとします。

その1つの要素の値を返すように、以下のセルの ... のところを書き換えて exception9(a) を定義してください。

[4]:
def exception9(a):
    ...

次のセルで動作を確認してください。

[5]:
print(exception9([1,2,2,2,2,2,2,2,2]))
print(exception9([4,4,4,4,4,2,4,4,4]))
print(exception9([9,9,9,9,9,9,9,9,3]))
None
None
None

▲複数行にまたがる条件式

複雑な条件式では複数行に分割した方が見やすい場合もありあます。 ここでは、式を複数行にまたがって記述する1つの方法を示します。 1つ目は、丸括弧で括られた式を複数の行にまたがって記述する方法です。 2つ目は、行末にバックスラッシュ \ を置く方法です。

[6]:
### 丸括弧で括る方法
x, y, z = (-1, -2, -3)
if (x < 0 and y < 0 and z < 0 and
    x != y and y != z and x != z):
    print('x, y and z are different and negatives.')

### 行末にバックスラッシュ(\) を入れる方法

x, y, z = (-1, -2, -3)
if x < 0 and y < 0 and z < 0 and \
    x != y and y != z and x != z:
    print('x, y and z are different and negatives.')
x, y and z are different and negatives.
x, y and z are different and negatives.

ifelifelse における条件の評価

ifelif による条件分岐では、if あるいは elif に続く条件式が True の場合、 それ以降の elif に続く条件式の評価は行われません。

以下のプログラムで x3, 0, -4 とした際に何が表示されるかを予想したのちに実行してみましょう。

特に、 x = -4 としたときの動作に注意してください。(x is zero. は表示されません。)

[7]:
x = 3  # example: 3, 0, -4

if x > 0:
    print('x is greater than zero.')
elif x < 0:
    print('x is less than zero, but x will be 0')
    x = 0
else:
    print('x is zero.')

print(x)
x is greater than zero.
3

練習

以下のプログラムはプログラマの意図どおりに動作しません。 print の出力内容から意図を判断して条件分岐を書き換えてください。

[8]:
x = -1
if x < 3:
    print('x is larger than or equal to 2, and less than 3')
elif x < 2:
    print('x is larger than or equal to 1, and less than 2')
elif x < 1:
    print('x is less than 1')
else:
    print('x is larger or equal to 3')
x is larger than or equal to 2, and less than 3

or もしくは and で結合された条件の評価

if文に与える条件が or もしくは and で結合されている場合、条件は左から順に評価され、 不要(以降の式を評価するまでもなく自明)な評価は省かれます。

たとえば、if a == 0 or b == 0: において 最初の式 a == 0True の場合、式全体の結果が True となることは自明なので、 二番目の式 b == 0 を評価することなく続く実行文グループが実行されます。

逆に、if a == 0 and b == 0: において、 最初の式が False の場合、以降の式は評価されることなく処理が進みます。

以下のセルで示す例の1行目で、x の値を 0, -4 に変更し、表示される内容を予想し、予想通りか確認してください。

[9]:
x = 10          # del x のエラーを抑制するため
y = 10

del x           # x を未定義に

if x > 5 or y > 5:
    print("'x' or 'y' is larger than 5")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_3502/449306055.py in <module>
      4 del x           # x を未定義に
      5
----> 6 if x > 5 or y > 5:
      7     print("'x' or 'y' is larger than 5")

NameError: name 'x' is not defined
[10]:
x = 10
y = 10          # del y のエラーを抑制するため

del y           # y を未定義に

if x > 5 or y > 5:
    print("'x' or 'y' is larger than 5")
'x' or 'y' is larger than 5

3項演算子(条件式)

Pythonでは以下のように if ... else を1行に書くこともできます。

[11]:
x = 0
sign = 'positive or zero' if x >= 0 else 'negative'
print(sign)
positive or zero

これは、以下と等価です。

[12]:
x = 0
if x >= 0 :
    sign = 'positive or zero'
else:
    sign = 'negative'
print(sign)
positive or zero

練習の解答

以下は解答例です。これ以外にも様々な解答があり得ます。

[13]:
def exception3(x,y,z):
    if x==y:
        return z
    elif x==z:
        return y
    else:
        return x
[14]:
def exception9(a):
    x = a[0] + a[1] + a[2]
    y = a[3] + a[4] + a[5]
    z = a[6] + a[7] + a[8]
    if x==y:
        return exception3(a[6], a[7], a[8])
    elif x==z:
        return exception3(a[3], a[4], a[5])
    else:
        return exception3(a[0], a[1], a[2])

練習の解説

最後の練習では、条件文の順番を修正する必要があります。 条件は上から順に処理され、式が真の場合にその「直後の実行文グループのみ」が処理されます。

[15]:
x = -1
if x < 1:
    print('x is less than 1')
elif x < 2:
    print('x is larger or equal to 1, and less than 2')
elif x < 3:
    print('x is larger or equal to 2, and less than 3')
else:
    print('x is larger or equal to 3')
x is less than 1
[ ]: