LoginSignup
0
0

More than 3 years have passed since last update.

動かしながら学ぶPython入門~その3:条件演算と条件分岐~

Posted at

はじめに

この記事は、連載です。
前回の動かしながら学ぶPython入門~その1:ソースファイル作成から画面に表示まで~から動かしながら学ぶPython入門~その2:変数操作と画面入力~を先に読んでからのほうが理解しやすいと思います。

タイトルに【コラム】とついているセクションは、動作や書式に直接の関係はありません。
ちゃっちゃと動かしてみたい人は読み飛ばしても問題ありません。
もちろん、せっかく書いたので読んでもらえたほうが嬉しいです。

対象

  • Pythonの初歩中の初歩を学習したい人

執筆時の環境

  • OS: Windows10
  • Python: 3.7.3
  • エディタ:VSCode

本文中の用語

用語 概略
ターミナル コマンドでコンピュータに命令を出すインターフェース
Windowsだと"コマンドプロンプト"や"PowerShell"が標準
Pythonインタプリタ Pythonのソースコードの解釈と実行を行うアプリケーション
詳しくは[コラム][インタプリタとは]を参照
ソースファイル アプリケーションの元となる、プログラム言語の決まった書式で書かれたファイル

条件演算をやってみる(※例題なし)

条件演算とは

Pythonに限らず、プログラミングでは条件に応じて処理を変えることが頻出する。
この時、等価大小など条件を評価するための演算を条件演算という。

条件演算は、演算結果として条件に合致するか否かを表す、TrueorFalseの2値のみを持つようになっている。
Pythonではbool型があるのでboolが返る。boolintのサブクラスで、0False0以外をTrue(1)に丸めるようになっている。

条件演算子

実際にプログラミングするにあたって、条件の合否を組むのに使うのが条件演算子
Pythonでは次のような条件演算子が存在する。

演算子 意味 使用例
== 左辺と右辺の値が等しい x == y
!= 左辺と右辺の値が異なる x != y
> 左辺の値が右辺の値を超過 x > y
>= 左辺の値が右辺の値以上 x >= y
< 左辺の値が右辺の値未満 x < y
<= 左辺の値が右辺の値以下 x <= y
is 左辺と右辺のオブジェクトが等しい x is y
is not 左辺と右辺のオブジェクトが異なる x is not y
in 左辺の値を右辺に含む x in y
not in 左辺の値を右辺に含まない x not in y

Pythonに限らず、主なプログラム言語において=右辺を左辺に代入を表すので、等値の条件は===を2つ連続して書く。

また、以上・以下の=については必ず>/<の後に来ないといけない。

対話モード
>>> 10 <= 0
False
>>> 10 =< 0
  File "<stdin>", line 1
    10 =< 0
        ^
SyntaxError: invalid syntax

恐らく、特にわかりにくいのがis/is not==/!=の違いだと思う。
まず、==/!=については値が等しいかどうかを判定するので、オブジェクトとしての等価判定はしない
例えば、次の例はTrueと評価される。

対話モード
>>> [1, 2, 3] == [1, 2, 3]
True

ところが、is/is notでは値だけではなくオブジェクトとして等価かどうかも判定するので値が等しいだけのものはFalseと評価される。

対話モード
>>> [1, 2, 3] is [1, 2, 3]
False

この使い分けは、慣れるまで結構混乱するのだが、要素一つ一つをオブジェクトとして見る感覚がついて来ると、だんだん使い分けられるようになる。

ちなみに、例のように全く内容が同じlistオブジェクトを、それぞれ変数に格納して、実際にオブジェクトのidを見てみると、別物であることがわかる。

対話モード
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a)
1453917102792
>>> id(b)
1453917600392

ブール演算子で条件式を組み合わせる

条件式を組み立てる時、2つ以上の条件式をどちらも満たすどれかを満たすのような組み方をしたくなる時がある。
前述の通り、条件演算の結果はboolで返される為、ブール演算子を使うことで実現できる。

Pythonでは次のようにブール演算子を記述する。

演算子 意味 使用例
and 左辺の評価がFalseの時は左辺の値を、Trueの時は右辺の値を返す x == y and x < z
or 左辺の評価がTrueの時は左辺の値を、Falseの時は右辺の値を返す x == y or x < z
not 条件項の値がTrueならFalse,FalseならTrueにする not x == y

Pythonでは、条件式を()などで囲う既定はないが、複数の条件式をつなぐ時は条件ごとに()で囲われているほうが可視性はいいと思う。

対話モードで実行
>>> 10 == 10.0 and 3 < 5
True
>>> (10 == 10.0) and (3 < 5)
True

また、ブール演算子は複数つなげて書くこともできる。

対話モードで実行
>>> (10 == 10.0) and (3 < 5) and ('a' == 'b') 
False

この時、異なるブール演算子を組み合わせる場合、and>orの順で優先度があるため()の有無で結果が異なる場面があることに注意が必要。
例えば、次の例はorの演算を明示的に先行させるかどうかで結果が異なる。

対話モードで実行
>>> (10 == 10.0) or (3 < 5) and ('a' == 'b')
True
>>> ((10 == 10.0) or (3 < 5)) and ('a' == 'b')
False

ちなみに、ブール演算子は各項をブール値として評価した場合として処理する為、実は値自体がブール値である必要はない。
例えば、次の例は左辺の0をブール値としてFalseとして扱った結果、右辺の値を返している。

対話モードで実行
>>> 0 or 12
12

ただし、notだけは値をブール値として評価した結果の逆値を返すため、必ずbool値が返る。

対話モードで実行
>>> not 1
False
>>> not 0
True

基本的には条件式の接続に使うと思うが、一応、公式でもこの特性を生かした例が載っているので、参考程度に見てみるといい。

条件分岐を使ってみる

Pythonにおける条件分岐は次の種類がある

識別子 意味
if 条件式がTrueならブロック下の処理を実行する
elif ifの条件式がFalseの時、条件式がTrueならブロック下の処理を実行する
else if,elif共に条件式がFalseの時、ブロック下の処理を実行する

if

一番基本の条件分岐で、ifに続いて条件式を記載し、終端の:後に改行・インデントしたうえで条件成立時の処理を記述する。

書式
if 条件式:
    条件成立時の処理

ifに限らないが、処理ブロック部分は対話モードだとと表示されるので、続けてインデントして入力する。

対話モードで実行
>>> if x > 10:
...     x = 10
...
>>> print(x)
10

対話モードでは、処理ブロックの終わりで改行しないとエラーになる。
ソースファイル実行では、改行してもしなくて問題なく認識される。

対話モードで実行
>>> if x > 10:
...     x = 10
... print(x)
  File "<stdin>", line 3
    print(x)
        ^
SyntaxError: invalid syntax

なお、処理ブロック部のインデントがずれていると、その時点でエラーになる。

対話モードで実行
>>> if x > 10:
... x = 10
  File "<stdin>", line 2
    x = 10
    ^
IndentationError: expected an indented block

例題

変数x,y2つの数値を標準入力から受けて、足した値を表示するプログラムを作った。

if_only.py
x = float(input(">>>"))
y = float(input(">>>"))
print(x + y)

このプログラムではx,yの入力値は無制限なので、10.0を超える入力値の時は10.0に丸める処理を追加してみよう

また、丸めた際にはそのことをxを10.0に制限しました(yの場合は先頭文字はy)というメッセージでターミナルに出力すること。
なお、数値以外の入力があってもエラーが出るが、この例題においては対応は不要とする。

実行例
> .\if_only.py
x = 1.0
y = 5.0
6.0
実行例
> .\if_only.py
x = 12
y = 23
xを10.0に制限しました
yを10.0に制限しました
20.0

回答例を見る
x = float(input("x = "))
y = float(input("y = "))

if x > 10.0:
    print("xを10.0に制限しました")
    x = 10.0

if y > 10.0:
    print("yを10.0に制限しました")
    y = 10.0

print(x + y)

else

条件分岐において、条件式が成立ならAの処理、不成立ならBの処理というようなシチュエーションも頻発する。
そのような時は、ifと抱き合わせる形でelseを使う。

通常のifの構文後(ifの処理ブロック部の後)に、インデントを戻してelse:と書いてから、改行・インデントしてifの条件が不成立時の処理を書く。

書式
if 条件式:
    条件成立時の処理
else:
    条件不成立時の処理

elseifと抱き合わせなので、当然単体では使えない。

対話モードで実行
>>> else:
  File "<stdin>", line 1
    else:
       ^
SyntaxError: invalid syntax

また、対話モードではifの処理ブロック部の後に改行すると、そのif自体が閉じてしまうので、else:の記述は処理ブロックの後改行せずに、インデントだけを戻して記述する。

対話モードで実行
>>> x = 5
>>> if x > 10:
...     x = 10
... 
>>> else:
  File "<stdin>", line 1
    else:
       ^
SyntaxError: invalid syntax
対話モードで実行
>>> x = 5      
>>> if x > 10:
...     x = 10
... else:
...     x = 1
... 
>>> print(x)  
1

ソースファイル実行では、どちらでも認識されるが、改行しないほうが見やすいように思う。

例題

ifの例題と同じベースのプログラムを用意した。

if_else.py
x = float(input(">>>"))
y = float(input(">>>"))
print(x + y)

xyの合計値を表示後、**合計値が20.0を超える時はx + yは20より大きいです20.0以下の時はx + yは20以下ですとターミナルrに出力してみよう。

なお、数値以外の入力があってもエラーが出るが、この例題においては対応は不要とする。

実行画面
> .\if_else.py
x = 12
y = 2
14.0
x + yは20以下です
実行画面
> .\if_else.py
x = 12
y = 12
24.0
x + yは20より大きいです

回答例を見る
if_else.py
x = float(input("x = "))
y = float(input("y = "))
result = x + y

print(result)

if  result > 20.0:
    print("x + yは20より大きいです")
else:
    print("x + yは20以下です")

この例では20.0超過の条件で判定しているが、もちろん20.0以下の条件判定でif,elseの処理内容が反転してる形でもよい。

elif

ifelseで条件の成立、不成立時それぞれに対応できるようになったが、実際のシチュエーションでは、3条件以上の分岐も普通に存在する。
if第一条件成立時に次のifで第二条件を見て・・・と組んでもいいのだが、条件が多いとどんどんネストが深くなってしまう。

そこで、ifの条件が不成立時にelseに行く前に別の条件を見ることができるelifが存在する。

通常のifの構文後(ifの処理ブロック部の後)に、インデントを戻してelif 条件式:と書いてから、改行・インデントしてifの条件が不成立時且つ、elifの条件式が成立時の処理を書く。

書式
if 第一条件式:
    第一条件成立時の処理
elif 第二条件式:
    第一条件不成立時且つ第二条件成立時の処理

elifelse同様、ifとの抱き合わせなので、単体では使えない。

対話モードで実行
>>> elif 5 > 10:
  File "<stdin>", line 1
    elif 5 > 10:
       ^
SyntaxError: invalid syntax

また、elifは同一のif]に対して複数定義することができ、すべてのif,elifの条件不成立時のelseを併用することもできる。

対話モードで実行
>>> x = 300
>>> if x < 5:
...     x = 5
... elif x < 7:
...     x = 7
... elif x > 100:
...     x = 100
... else:
...     x = 0
...
>>> print(x)
100

例題

ifの例題と同じベースのプログラムを用意した。

if_else.py
x = float(input(">>>"))
y = float(input(">>>"))
print(x + y)

ifの例題同様、変数x,yのともに 10.0を超える入力値の時は10.0に丸め、さらに 5.0未満でも5.0に丸める処理を追加してみよう

また、丸めた際にはそのことをxを10.0に制限しました(yの場合は先頭文字はy, 丸め先が5.0の場合は10.0のところが5.0)というメッセージでターミナルに出力すること。
なお、数値以外の入力があってもエラーが出るが、この例題においては対応は不要とする。

実行画面
> .\if_elif.py
x = 5
y = 8
13.0
実行画面
> .\if_elif.py
x = 12.0
y = 2.0
xを10.0に制限しました
yを5.0に制限しました
15.0

回答例を見る
if_else.py
x = float(input("x = "))
y = float(input("y = "))

if x > 10.0:
    print("xを10.0に制限しました")
    x = 10.0
elif x < 5.0:
    print("xを5.0に制限しました")
    x = 5.0
else:
    pass

if y > 10.0:
    print("yを10.0に制限しました")
    y = 10.0
elif y < 5.0:
    print("yを5.0に制限しました")
    y = 5.0
else:
    pass

print(x + y)

この例ではelse節を記述してpassとしているが、これはelse節が何も処理しないことを明示するもので、動作上はあっても無くても同じ動きをする。

ただ、明示することで、第3者や実装者自身が時間を空けて見返した時などに、すべての条件が不成立の時の処理を書き漏れ・検討漏れではないことを示すという意味があるので、書くようにしている。

【おまけ】3項演算子

条件で処理を切り分けるのはif~elif,elseだが、条件に応じて値を決定するだけならば、3項演算子も使える。

Pythonではこのように記述する。

書式
条件成立時の値 if 条件文 else 条件不成立時の値

例えば、絶対値を計算するために負数の時だけ-1を掛けるという処理をしたければ、3項演算子を使って係数を1-1から決定してあげるとスマートに書ける。(abs関数あるけど…)

ternaly_operator.py
x = float(input("x = "))

x *= 1 if x >= 0 else -1
print(x)
実行画面
> .\ternaly_operator.py
x = 10
10.0
実行画面
> .\ternaly_operator.py
x = -10
10.0

if,elseでも対応可能だが、値選択ごときで何行も書きたくはないので、覚えておくとスマートに書けて便利。
未検証だが、if,elseに対して1行記述なので、インタプリタの解読が多分早いと思う(違ったらごめんなさい)。

【コラム】Pythonにおける処理ブロックの区切り方

条件分岐を使うにあたって、条件に該当した部分とそれ以外を区分ける必要がある。
条件分岐だけに限らず、繰り返し処理(ループ)の範囲や、共通処理(関数)の範囲として複数の処理の塊を区分けるのは、プログラミングでは頻出する。

Pythonでは、そういったブロックの範囲をインデントで表すことになっている。
他の言語では、(){}などで括った範囲で表すことも多いが、括った範を示す可視性の観点でインデントも合わせて使うことが慣例的に多い。
ただ、初学者などの理由から、こういった慣例を知らなかったりしてインデントが崩れた構文で書いてしまっても()があっていれば動くので、指摘されたりするまで気づかないこともある。

この点、Pythonでは言語の仕様としてインデントが定められているので、動かすためには誰であっても同一のインデントにそろえる必要があり、動いた時点でブロック回りの可視性がそれなりに担保できるという利点がある。

次回

動かしながら学ぶPython入門~その4:繰り返し~

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0