3. 条件によって動作を変える¶
今回は、条件によってプログラムの動作を変える方法を学んでいきます。
3.1. 命題と論理式¶
まずは、高校数学の復習です。
命題
正しいか正しくないかを判定できる文や式
例
\(3\)は\(2\)より大きい
\(3\)は偶数である
命題が正しいときを真(true)、間違っているときは偽(false)といいます。
だから、「\(3\)は\(2\)より大きい」は真ですが、「\(3\)は偶数である」は偽となります。
Python では、論理式として命題を表現することができます。
論理式:Python における命題
評価すると論理値(True
もしくは False
)になる式
このような論理式を表現するため、次のような演算子を提供しています。
数式 |
Python |
説明 |
---|---|---|
\(x < y~~~~~\) |
|
x は y より小さいかどうか |
\(x \le y\) |
|
x は y 以下かどうか |
\(x > y\) |
|
x は y より大きいかどうか |
\(x \ge y\) |
|
x は y 以上かどうか |
\(x = y\) |
|
x は y と等しいかどうか |
\(x \ne y\) |
|
x は y と等しくないかどうか |
\(x \in y\) |
|
x は y に含まれるかどうか |
\(x \not\in y\) |
|
x は y に含まれないかどうか |
\(x \land y\) |
|
x かつ y |
\(x \lor y\) |
|
x または y |
\(\lnot x\) |
|
x の否定 |
例題(論理式)
次の命題を論理式として評価してみよう。
\(3\)は\(2\)より大きい
\(3\)は偶数である
\(\pi\)は3より大きく、\(3.18\)より小さい (
from math import pi
)\(121\)は\(11\)の倍数でない
文字
"e"
は文字列"Hello"
に含まれる
[1]:
3 > 2
[1]:
True
[2]:
3 % 2 == 0
[2]:
False
[3]:
from math import pi
3.0 < pi < 3.18
[3]:
True
[4]:
121 % 11 != 0
[4]:
False
[5]:
"e" in "hello"
[5]:
True
形式論理学
命題の概念は、命題論理につながっていき、 コンピュータ上で論理や思考をプログラミングするとき重要になります。
3.2. 条件分岐¶
プログラムは、原則、上から順番に[A]→[B]のように評価してゆきます。
しかし、条件によっては、評価するプログラムを[X]か[Y]のように切り替えたいことがあります。 そのようなときは、if文と呼ばれる制御構造を用います。
if文や条件分岐の考え方は難しいものではありません。 しかし、Python には、インデントによってコードブロックを示すなど、 独特なクセがあります。 いくつか書き方のパターンを見て、書き方をマスターしましょう。
重要: インデント(字下げ)
コードの前の空白をインデントといいます。 (Python はインデントの深さでコードブロックの始まりと終わりを表ます。)
3.2.1. 基本形¶
まず簡単な例題をみながら、しくみと書き方を理解しましょう。
例題(偶数と奇数)
整数値を入力から読み、 偶数の場合はeven
, 奇数の場合はodd
と表示しよう。
入力
10
出力
even
実際に、入力する値を変えて、結果の変化を試してみましょう。
[6]:
# x = int(input())
x = 10
if x % 2 == 0:
print("even")
else:
print("odd")
even
3.2.2. 何も処理しない場合¶
条件分岐したとき、一方は何も処理しない場合があります。
Python では、「何も実行しない」というプログラムを意味する特殊な文として、 pass
文があります。トランプゲームの「パス」という同じです。 だから、print("odd")
の代わりにpass
にすると、何も実行されません。
[7]:
# x = int(input())
x = 10
if x % 2 == 0:
print("even")
else:
pass
even
もうひとつ、else:
自体は、何も実行しないときは省略できます。 だから、省略しても構いません。(こちらの書き方が好まれます。)
else:を省略
[8]:
# a = int(input())
x = 10
if x % 2 == 0:
print("even")
even
3.2.3. ブロック:複数行のコードを処理する¶
分岐処理によっては、分岐先で複数行のプログラムを評価したいことがあります。 同じ深さのインデントが続くときは、コードブロック(つまり複文)として順次、評価されます。
[9]:
# x = int(input())
x = 3
if x % 2 != 0:
print("***")
print("***")
print("***")
***
***
***
ここはインデントによるコードブロックの書き方をしっかり理解しましょう。
コードブロックとインデントの深さ
Pythonは、同じインデントの深さのコードをひとまとまりの処理(コードブロック)とします。 次のように入れ子として書くことができます。
if a != 0:
print(a)
if b != 0:
print(b)
if c != 0:
print(c)
print("b")
print("a")
print()
3.2.4. 複数の条件があるとき¶
if文のブロックには、if文を書くことができます。 これにより、より複雑なプログラムが書けるようになります。
例題(複数の条件))
入力1行から空白で区切られた整数値a,bを読みます。 aがbより大きければbig
、 等しければsame
、 そうでなければ small
と表示しよう。
入力
3 2
出力
big
[10]:
#a, b = map(int, input().split())
a, b = 3, 2
if a > b:
print("big")
else:
if a == b:
print("same")
else:
print("small")
big
else:
のあとに、すぐに if文が続くときは、elif
で書き直すことができます。
[11]:
#a, b = map(int, input().split())
a, b = 3, 2
if a > b:
print("big")
elif a == b:
print("same")
else:
print("small")
big
よくある望ましくない例(あまり効率のよくない書き方)
何度も条件分岐をする
if a > b:
print("big")
if a == b:
print("same")
if a < b:
print("small")
最後がelifで終わっている
if a > b:
print("big")
elif a == b:
print("same")
elif a < b:
print("small")
3.3. 条件式(三項演算子)¶
Pythonでも、if文を条件式として1行に書くことができます。
<真のときの式> if <論理式> else <偽のときの式>
三項演算子
if式は、C/C++やJavaの三項演算子に相当します。
三項演算子の場合
<論理式> ? <真のときの式> : <偽のときの式>
例題(条件式)
入力1行から空白で区切られた整数値a,bを読みます。 aとbを比較して大きい値を表示しよう。
入力
3 2
出力
3
if式で書いた例
[12]:
#a, b = map(int, input().split())
a, b = 3, 2
print(a if a > b else b)
3
if式(三項演算子)は、ソースコードが冗長になるのを防いでコンパクトに書くことができます。 ぜひ、積極的に利用してみましょう。
if文で書いた例(冗長な書き方)
[13]:
# a, b = map(int, input().split())
a, b = 3, 2
if a > b:
print(a)
else:
print(b)
3
3.4. 繰り返し¶
3.4.1. while文¶
while文は、特殊な条件分岐の構文になります。 if文の代わりに、while文を用いると、 条件PがTrueの間は``[X]``を繰り返します。
while文: 条件を満たす限り、繰り返す
[14]:
a = 5
while a > 0:
print(a)
a = a - 1
5
4
3
2
1
ちなみに、「if文は条件を満たせば、高々1回実行される」構造でした。
[15]:
a = 5
if a > 0:
print(a)
a = a - 1
5
無限ループ
while文の条件がいつまでも真で繰り返しが止まらなくなること
先程の例では、while
文の中でa = a - 1
が処理されないと、いつまでもa > 0
になるため、無限ループになります。
無限ループの例
a = 5
while a > 0:
print(a)
a = a - 1
無限ループは、頻繁に発生し、主要なバグの原因になります。アプリケーションが反応しなくなる不具合の原因は、ほとんどが「予期しない無限ループに陥っている」と言われています。while
文を書くときは、無限ループにならないように注意して書かなければなりません。
防衛的プログラミング( Defensive Programming)
ソフトウェア工学でより詳しく学びますが、 バグや不具合が発生しないようにコードの書き方を選びます。 (動けば良いというのは、20世紀のプログラミングです。)
3.4.2. for文¶
無限ループは、初学者から上級者まで発生させやすいバグの原因になります。 解説を読んでいるときは、「そんなマヌケなコードは書きませんよ(絶対)」と笑っていても、 結構、頻繁に発生させて凹みます。
無限ループを避ける確実な手段は、while
文を使わないことです。 for/in
文は、繰り返す回数を指定でき、無限ループを避ける確実な方法です。
N回繰り返したいとき
for i in range(N):
print(i) # 繰り返す処理
特別な事情がない場合は、繰り返しはfor
文を用いるようにしましょう。 特に、for i in range(N):
は、\(N\)回繰り返すときの定番の書き方です。
for 文の変数
変数 i
には0から始まる整数が繰り返しの回数分に割り当てられます。 (リストと同じく0 から始まります。)
[16]:
for i in range(10):
print(i, '*' * i)
0
1 *
2 **
3 ***
4 ****
5 *****
6 ******
7 *******
8 ********
9 *********
3.4.3. シミュレーション¶
シミュレーションは、1ステップずつ値を更新させながら、未来を予測する計算手法です。 プログラミングの得意な分野のひとつとなっています。
例題(お米)
お米は、一粒から1本の苗になります。 苗は、10本の穂を実らせ、各稲穂には60粒のお米が実ります。 つまり、1粒は1年後に600粒になります。
1粒の稲を1億粒以上に増やすには、何年かかるか求めてみよう。
等比数列から計算してもよいですが、シミュレーション(繰り返し)で書いてみましょう。
while文で書いたとき
[17]:
START = 1
GOAL = 1_0000_0000 # _位取り
year = 0
n = START
while n < GOAL:
n = n * 600
year = year + 1
print(year)
3
for文で書くときは、少し大きめの繰り返し回数を指定し、 条件を満たしたら、ループを抜けるbreak
文を使います。
[18]:
START = 1
GOAL = 1_0000_0000 # _位取り
n = START
for year in range(1, 1000):
n = n * 600
if n >= GOAL:
break
print(year)
3
break
文
while文やfor文の繰り返しを強制的に抜け出す
3.5. 演習問題¶
繰り返しは、次回以降、リストや文字列とあわせて練習していきます。
今回は、まず条件分岐に慣れましょう。少し予習で繰り返しも混ざっています。
インデントのエラーに困ったら
Python は、コードをコピペすると、空白記号とタブ記号が混ざって、 インデント周りのエラーが発生しやすくなります。 どうにかなりませんかと言われますが、正直、コピペしないで、 自分でインデントを統一的に書くのが確実です。