はじめに
この記事は、連載です。
前回の動かしながら学ぶPython入門~その1:ソースファイル作成から画面に表示まで~から動かしながら学ぶPython入門~その2:変数操作と画面入力~を先に読んでからのほうが理解しやすいと思います。
タイトルに【コラム】
とついているセクションは、動作や書式に直接の関係はありません。
ちゃっちゃと動かしてみたい人は読み飛ばしても問題ありません。
もちろん、せっかく書いたので読んでもらえたほうが嬉しいです。
対象
-
Python
の初歩中の初歩を学習したい人
執筆時の環境
- OS: Windows10
- Python: 3.7.3
- エディタ:VSCode
本文中の用語
用語 | 概略 |
---|---|
ターミナル | コマンドでコンピュータに命令を出すインターフェース Windowsだと"コマンドプロンプト"や"PowerShell"が標準 |
Pythonインタプリタ | Pythonのソースコードの解釈と実行を行うアプリケーション 詳しくは[コラム][インタプリタとは]を参照 |
ソースファイル | アプリケーションの元となる、プログラム言語の決まった書式で書かれたファイル |
条件演算をやってみる(※例題なし)
条件演算とは
Pythonに限らず、プログラミングでは条件に応じて処理を変えることが頻出する。
この時、等価
や大小
など条件を評価するための演算を条件演算という。
条件演算は、演算結果として条件に合致するか否かを表す、True
orFalse
の2値のみを持つようになっている。
Pythonではbool型があるのでboolが返る。boolはintのサブクラスで、0
をFalse
、0
以外を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
,y
2つの数値を標準入力から受けて、足した値を表示するプログラムを作った。
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:
条件不成立時の処理
>>> 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の例題と同じベースのプログラムを用意した。
x = float(input(">>>"))
y = float(input(">>>"))
print(x + y)
x
とy
の合計値を表示後、**合計値が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より大きいです
回答例を見る
elif
ifとelseで条件の成立、不成立時それぞれに対応できるようになったが、実際のシチュエーションでは、3条件以上の分岐も普通に存在する。
if第一条件成立時に次のifで第二条件を見て・・・と組んでもいいのだが、条件が多いとどんどんネストが深くなってしまう。
そこで、ifの条件が不成立時にelseに行く前に別の条件を見ることができるelifが存在する。
通常のifの構文後(ifの処理ブロック部の後)に、インデントを戻してelif 条件式:
と書いてから、改行・インデントしてifの条件が不成立時且つ、elifの条件式が成立時の処理を書く。
if 第一条件式:
第一条件成立時の処理
elif 第二条件式:
第一条件不成立時且つ、第二条件成立時の処理
elifもelse同様、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の例題と同じベースのプログラムを用意した。
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
回答例を見る
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関数あるけど…)
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:繰り返し~