タートルグラフィックスで学ぶ Python のキホン 第 5 章
教材コード
第 5 章

条件で分ける

「もし〜なら」.状況を見て,やることを変えさせます.

ここまでのプログラムは,書いた命令が必ず上から順にすべて実行されていました. これを順次実行といいます. 前の章では,入力や乱数を使って「毎回ちがう数」を扱えるようになりましたが, 数が変わってもやることは同じでした.

今回習う条件分岐を使うと, 状況に応じて,実行する命令そのものを変えることができます. 「1 と入力されたら家を,2 なら星を描く」 「90 点以上なら『秀』と表示する」 「大吉のときだけ,お祝いの星を描く」. プログラムが,はじめて判断をするようになります.

順次実行しかできなかった機械が,ここではじめて賢く見えはじめます.

この章でできるようになること
  • if の書き方(コロンと字下げ)がわかり,条件に応じた処理が書ける
  • == != < <= > >= を使って条件式が書ける
  • ==(比べる)と =(入れる)を区別できる
  • else で 2 つに,elif でいくつにも分けられる
  • and・or・not で条件を組み合わせられる
  • 条件を入れ子にした処理が読める・書ける
  • 変数がどこから見えるか(有効範囲)を説明でき,NameError になる場合を避けられる
  • 乱数と条件分岐を組み合わせて,おみくじやじゃんけんが作れる

5.1 もし〜なら — if

5.1.1 実行の流れを変える

次のプログラムを開いて,実行してみてください. 正三角形を描いたあと,1 辺が 100 より大きいときだけ 文字を書き足します.

if1.py
from turtle import *

length = 140          # ← ここを 60 に変えて,もう一度実行してみる

pensize(3)
pencolor("teal")

fd(length)
lt(120)
fd(length)
lt(120)
fd(length)
lt(120)

if length > 100:
    pencolor("crimson")
    pu()
    goto(length / 2, -45)
    pd()
    write("大きい三角形", align="center", font=("Arial", 20, "bold"))

ht()
done()
大きい三角形
図 5.1 length = 140 のとき.条件が成立したので文字が書かれた.

length = 140 を length = 60 に書き換えて, もう一度実行してください.今度は文字が出ません. 同じプログラムなのに,実行される命令が変わりました.

大きい三角形
図 5.2 length = 140 → 文字が出る
図 5.3 length = 60 → 文字は出ない

5.1.2 if の書き方

if の基本形
if 条件式:
    処理

書くときの約束は 2 つだけです.どちらも忘れやすいので,声に出して覚えてください.

  1. if の行のおしまいにコロン : を打つ.
  2. 次の行から字下げ(インデント)する.半角スペース 4 つ.

字下げされている行が,「条件が成立したときに実行する部分」です. 字下げをやめたところで,if の中身はおしまいになります.

どこまでが if の中身か
x = 15

if x > 10:
    print("A")       ← if の中(x > 10 のときだけ実行)
    print("B")       ← if の中
print("C")           ← if の外(いつでも実行される)
block.py
x = 15

if x > 10:
    print("A")
    print("B")
print("C")

print("----")

x = 5

if x > 10:
    print("A")
    print("B")
print("C")

上半分では A B C の 3 行,下半分では C だけが出ます. 字下げされた 2 行が,まとめて実行されたり,まとめて飛ばされたりするわけです. この「まとまり」をブロックといいます.

字下げは飾りではない Python では,字下げがブロックの範囲そのものを表します. 見やすくするための飾りではなく,文法の一部です. 第 2 章で「行の先頭の空白には意味がある」と言ったのは,このことでした.
字下げまわりのエラー
  • コロンを忘れる → SyntaxError: expected ':'
  • 字下げを忘れる → IndentationError: expected an indented block
  • 字下げの幅がそろっていない(3 つと 4 つが混ざるなど) → IndentationError: unexpected indent
  • タブ文字とスペースが混ざる → TabError.見た目は同じでも別の文字なので厄介です.この教材のコード欄は Tab キーを押すとスペース 4 つが入ります.
何もしないブロックは書けない ブロックの中身を1 行も書かないと,これもエラーになります. 「ここでは何もしない」とわざわざ書きたいときは, pass という命令を 1 行だけ置きます.
何もしないと書く
if n == 5:
    pass                      # 5 のときは何もしない
else:
    print("5 ではありません")
もっとも,この例は if n != 5: と書けば pass は要りません. まず条件のほうを見直すのが先で, pass は形をどうしても残したいときの逃げ道だと思ってください.

5.1.3 流れ図で見る

プログラムの流れを絵にしたものを流れ図(フローチャート)といいます. ひし形が「条件を調べるところ」,四角が「処理」です. else を書かない if は,次のような流れになります.

条件式不成立成立処理
図 5.4 if だけの流れ図.成立したときだけ処理を通る.
虫食い虫食い 5-A 条件を 1 行で書く

正三角形を描いたあと,1 辺が 100 より大きいときだけ 赤い文字を書き足します.____ の行に, if の 1 行を書いてください. コロンを忘れないこと.

ヒント 書き終わったら length を 60 に変えて実行し, 文字が出なくなることも確かめてください.
fill1_if.py
from turtle import *

length = 150

pensize(3)
pencolor("darkcyan")

fd(length)
rt(120)
fd(length)
rt(120)
fd(length)
rt(120)

# 「もし length が 100 より大きければ」という 1 行を書く
____
    pencolor("crimson")
    pu()
    goto(length / 2, -45)
    pd()
    write("大きい", align="center", font=("Arial", 26, "bold"))

ht()
done()

5.2 くらべて True か False を出す

5.2.1 6 つの比べ方

if のうしろに書く length > 100 のような式を 条件式といいます. 2 つの値を比べる記号を比較演算子といい,全部で 6 つあります.

演算子書き方成立するのは読み方
==a == ba と b が等しいときイコールイコール
!=a != ba と b が等しくないときノットイコール
>a > ba が b より大きいとき大なり
<a < ba が b より小さいとき小なり
>=a >= ba が b 以上のとき(等しいときも成立)大なりイコール
<=a <= ba が b 以下のとき(等しいときも成立)小なりイコール
>= の順番 >= は => ではありません. 不等号が先,イコールが後です. 数学で ≧ と書くときの順番と同じだと覚えてください.

5.2.2 条件式は True か False になる

条件式は,計算されるとTrue(成立)か False(不成立)のどちらかになります. この 2 つしか値をとらない型を bool(ブール)型といいます. 前の章で習った int・float・str に続く 4 つめの型です.

compare.py
x = 7

print(x == 7)      # True
print(x != 7)      # False
print(x > 10)      # False
print(x < 10)      # True
print(x >= 7)      # True
print(x <= 6)      # False

print(type(x > 10))   # <class 'bool'>

if は,このうしろの値が True なら中身を実行し, False なら飛ばします.それだけの仕組みです.

大文字・小文字に注意 True と False は,先頭だけ大文字です. true や TRUE と書くと NameError になります.

5.2.3 文字列も比べられる

== と != は,数だけでなく文字列にも使えます.

strcmp.py
name = input("名前を入力してください > ")

if name == "かめ":
    print("こんにちは,かめさん")

if name != "かめ":
    print(f"はじめまして,{name}さん")
文字列の比較 文字列を比べるときは,ダブルクォートを忘れないでください. if name == かめ: と書くと, 「かめ という変数」を探しに行って NameError になります. また,"かめ" と "カメ" と "亀" は すべて別の文字列です.前後に空白が入っていても別物になります.

5.2.4 == と = の違い

ここは毎年まちがえます 等しいかどうかを調べるのは,イコールを 2 つ並べた == です. イコール 1 つの = は,前の章で習った 代入(箱に入れる命令)でした. まったく別のものです.
書き方意味使う場所
x = 7x という箱に 7 を入れるふつうの行
x == 7x が 7 と等しいか調べる(True か False になる)if の条件式
= と == の使い分け
x = 7          # 代入.x が 7 になる
if x == 7:     # 比較.x が 7 かどうか調べる
    print("7 です")

if x = 7:      # ← これは SyntaxError
    print("7 です")
Python は親切にできている Python では if x = 7: と書くと文法エラーになるので, その場ですぐ気づけます. = と == の打ち間違いは,どんなに慣れた人でもやります. Python は,この間違いをそもそも書けないようにしてあるのです.
虫食い虫食い 5-B 比較演算子を選ぶ

コメントに書いたとおりの結果になるよう, ____ に比較演算子を入れてください. 使う記号は == != < <= > >= のどれかです.

fill2_compare.py
x = 7

print(x ____ 7)      # True  と出したい(等しい)
print(x ____ 7)      # False と出したい(等しくない)
print(x ____ 10)     # True  と出したい(より小さい)
print(x ____ 7)      # True  と出したい(以上)
print(x ____ 6)      # False と出したい(以下)

5.3 そうでなければ — else

「成立したらこちら,しなかったらあちら」と2 つに分けたいときは, else を使います.

if - else の形
if 条件式:
    処理A          ← 成立したときだけ実行
else:
    処理B          ← 成立しなかったときだけ実行
  • else の行にもコロンが要ります.
  • else のうしろには条件を書きません(「それ以外のすべて」という意味だからです).
  • if と else は同じ深さに書きます.
  • 処理A と処理B のどちらか一方だけが必ず実行されます.両方は実行されません.
条件式処理A処理B成立不成立
図 5.5 if - else の流れ図.道が 2 つに分かれ,またひとつに戻る.

5.3.1 入力に応じて描くものを変える

「番号を入力すると,その絵を描く」プログラムです.

else_picture.py
from turtle import *

print("描きたい絵の番号を入力してください(1: 家 / それ以外: 星)")
number = int(input("番号 > "))

pensize(3)

if number == 1:
    # ---- 家を描く ----
    print("家を描きます")
    pencolor("saddlebrown")
    length = 110
    lt(60)
    fd(length)
    rt(120)
    fd(length)
    rt(120)
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
else:
    # ---- 星を描く ----
    print("星を描きます")
    pencolor("goldenrod")
    length = 170
    rt(18)
    fd(length)
    rt(144)
    fd(length)
    rt(144)
    fd(length)
    rt(144)
    fd(length)
    rt(144)
    fd(length)
    rt(144)

ht()
done()

コンソールの入力行の 1 を 2 に書き換えて,実行し直してください. 描かれる絵が変わります.

図 5.6 1 を入力したとき
図 5.7 2 を入力したとき
ヒント if の中身も else の中身も, 何行でも書けます.字下げさえそろっていれば, その中でさらに pu() や pencolor() を使ってもかまいません. 長くなってきたら,コメントで # ---- 家を描く ---- のように見出しを付けると読みやすくなります.
虫食い虫食い 5-C 正方形か正三角形か

1 と入力されたら正方形を,それ以外なら正三角形を描きます. ____ を 2 か所埋めてください. 1 つめは比較の記号,2 つめは「そうでなければ」の 1 行です.

fill4_else.py
from turtle import *

n = int(input("1 なら正方形,それ以外なら正三角形 > "))

pensize(3)

if n ____ 1:
    pencolor("navy")
    fd(120)
    lt(90)
    fd(120)
    lt(90)
    fd(120)
    lt(90)
    fd(120)
    lt(90)
____
    pencolor("crimson")
    fd(120)
    lt(120)
    fd(120)
    lt(120)
    fd(120)
    lt(120)

ht()
done()

5.4 いくつにも分ける — elif

3 つ以上に分けたいときは elif を使います. elif は else if を縮めた言葉です.

if - elif - else の形
if 条件式1:
    処理A
elif 条件式2:
    処理B
elif 条件式3:
    処理C
else:
    処理D
  • elif はいくつでも並べられます.
  • 最後の else は省略できます(どれにも当てはまらなければ,何もしない).
  • 上から順に条件を調べ,最初に成立したものだけを実行します.
  • 1 つ実行したら,残りの elif は調べもしません.
条件式1条件式2処理C処理A処理B不成立不成立成立成立
図 5.8 elif の流れ図.上から順に調べ,どれか 1 つだけを通る.

5.4.1 評点をグレードに変える

成績は,評点に応じて 「秀」「優」「良」「可」「不可」の 5 段階に分けられます. これをプログラムにしてみましょう.

grade.py
print("評点をグレードに変換します")
score = int(input("評点(0〜100)を入力してください > "))

if score >= 90:
    grade = "秀"
elif score >= 80:
    grade = "優"
elif score >= 70:
    grade = "良"
elif score >= 60:
    grade = "可"
else:
    grade = "不可"

print(f"評点 {score} 点は「{grade}」です")

コンソールの入力行の数を 95,72,40 などに 変えて,すべての枝を通してみてください.

5.4.2 書く順番で結果が変わる

順番を間違えると全員「可」になる elif は上から順に調べます.だから, 細かい条件(きびしい条件)から先に書く必要があります.
順番を間違えた例
# ← まちがった順番
if score >= 60:
    grade = "可"        # 95 点でも,ここで決まってしまう!
elif score >= 70:
    grade = "良"        # ここには永久にたどりつかない
elif score >= 90:
    grade = "秀"

95 点のときを考えてみてください. まず score >= 60 を調べます.95 は 60 以上なので成立します. ここで grade = "可" が実行され,残りの elif は 調べられることなく飛ばされます.

エラーにならないバグ このプログラムはエラーになりません. ただ結果が間違っているだけです.こういう間違いが,いちばん見つけにくいバグです. elif を書いたら,それぞれの枝を必ず 1 回は通して 確かめる習慣をつけてください.

5.4.3 elif と「if を並べる」は違う

elif を使わず,if をいくつも並べて書くこともできます. しかし意味が変わります.

書き方動き
if - elif - elifどれか 1 つだけが実行される.1 つ決まったら残りは調べない
if - if - ifそれぞれ独立に調べられる.当てはまればいくつでも実行される
multi_if.py
score = 95

print("--- elif で書いた場合 ---")
if score >= 60:
    print("可以上")
elif score >= 70:
    print("良以上")
elif score >= 90:
    print("秀")

print("--- if を並べた場合 ---")
if score >= 60:
    print("可以上")
if score >= 70:
    print("良以上")
if score >= 90:
    print("秀")

前半は 可以上 の 1 行だけ, 後半は 可以上・良以上・秀 の 3 行が出ます. 「どれか 1 つを選びたい」のか「当てはまるものを全部やりたい」のかで 使い分けてください.

虫食い虫食い 5-D グレード判定の境目

評点をグレードに変える elif の, 境目の数が抜けています. ____ を埋めて完成させてください. 秀は 90 点以上,優は 80 点以上,良は 70 点以上,可は 60 点以上です.

fill4_grade.py
score = int(input("評点(0〜100)を入力してください > "))

if score >= ____:
    grade = "秀"
elif score >= ____:
    grade = "優"
elif score >= ____:
    grade = "良"
elif score >= ____:
    grade = "可"
else:
    grade = "不可"

print(f"評点 {score} 点は「{grade}」です")

5.5 条件を組み合わせる — and・or・not

「80 点以上かつ 90 点未満」のように, 2 つ以上の条件をまとめて判定したいことがあります. このときに使うのが論理演算子です.

演算子書き方成立するのは
andA and BA と B が両方とも成立するとき
orA or BA か B のどちらか一方でも成立するとき
notnot AA が成立しないとき(成立・不成立をひっくり返す)
記号ではなく英単語で書く Python の論理演算子は英単語です. そのぶん,声に出して読めばそのまま意味になります. 「score >= 80 and score < 90」は 「スコアが 80 以上 かつ スコアが 90 未満」です.

5.5.1 成立するかしないかの表

ABA and BA or Bnot A
TrueTrueTrueTrueFalse
TrueFalseFalseTrueFalse
FalseTrueFalseTrueTrue
FalseFalseFalseFalseTrue
logic.py
score = 85

print(score >= 80 and score < 90)     # True  (両方とも成立)
print(score >= 80 and score < 85)     # False (2 つめが不成立)
print(score < 60 or score >= 90)      # False (どちらも不成立)
print(score == 85 or score == 100)    # True  (1 つめが成立)
print(not (score >= 90))              # True  (90 以上ではない)

5.5.2 範囲で判定する

elif を使わずに,and だけで同じ判定を書くこともできます. 2 通りの書き方を並べて見てください.

range.py
score = int(input("評点(0〜100)を入力してください > "))

if score >= 90:
    print("秀")
if score >= 80 and score < 90:
    print("優")
if score >= 70 and score < 80:
    print("良")
if score >= 60 and score < 70:
    print("可")
if score < 60:
    print("不可")

こちらは if を並べているだけなので, それぞれの条件が重ならないように自分で気を配る必要があります. その代わり,どの行も単独で読めるという良さがあります. elif のほうが短く書けますが,どちらが読みやすいかは場合によります.

Python ならではの書き方 Python では,数学と同じように 80 <= score < 90 とつなげて書くことができます. score >= 80 and score < 90 とまったく同じ意味です.
Python だけの便利な書き方
if 80 <= score < 90:
    print("優")
数学で書くときと同じ形のまま書けます.

5.5.3 入力が正しいか確かめる

or は,「おかしな入力をはじく」のによく使います.

guard.py
from turtle import *

length = int(input("1 辺の長さ(10 以上 200 以下)を入力してください > "))

if length < 10 or length > 200:
    print(f"{length} では描けません.10 以上 200 以下にしてください.")
else:
    print(f"1 辺 {length} の正方形を描きます")
    pensize(3)
    pencolor("royalblue")
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
    lt(90)

ht()
done()

コンソールの入力行に 500 にして実行すると, 絵は描かれずに注意のメッセージだけが出ます. このように,処理する前に入力を確かめることを 入力チェックといいます.

ヒント この条件は not (10 <= length <= 200) とも書けます. 「10 以上 200 以下ではない」と読みます. どちらでも同じですが,読んで意味が分かるほうを選んでください.
虫食い虫食い 5-E 条件を組み合わせる

____ に and・or・not のどれかを入れて,コメントのとおりに動くようにしてください.

fill5_logic.py
age = int(input("年齢を入力してください > "))

# 18 歳以上 かつ 65 歳未満 のとき
if age >= 18 ____ age < 65:
    print("はたらきざかりです")

# 0 歳未満 または 120 歳より上 のとき(ありえない値)
if age < 0 ____ age > 120:
    print("その年齢はありえません")

# 20 歳以上 ではない とき
if ____ (age >= 20):
    print("お酒は飲めません")

5.5.4 組み合わせるときの順番とかっこ

and と or を同じ行に混ぜて書くと, どちらが先に計算されるかが問題になります. 第 3 章で,かけ算は足し算より先に計算されると習いました. 論理演算子にも,それとまったく同じように順番が決まっています.

順番演算子読み方
1(先)( ) の中かっこの中はいつでも最優先
2not〜でない
3andかつ
4(後)orまたは

つまり A or B and C は,A or (B and C) と 読まれます.(A or B) and C のつもりで書くと,結果が変わってしまいます.

priority.py
a = True
b = True
c = False

print(a or b and c)        # True    b and c が先 → True or False
print((a or b) and c)      # False   かっこの中が先 → True and False

print(not b and c)         # False   not b が先 → False and False
print(not (b and c))       # True    かっこの中が先 → not False
かっこは多めに 4 行とも,読み方が 1 つ変わるだけで答えがひっくり返っています. 迷ったら,かっこを付けてください. 余分なかっこがあってもエラーにはなりませんし,遅くもなりません. 読む人に書いた人の意図が伝わるという,大きな利点があります.

条件が 3 つ以上になるときは, かっこで「ひとかたまり」を作ってから組み合わせると読みやすくなります. 次は「2 つとも偶数」または「2 つとも 3 の倍数」のときだけ成立する条件です.

complex_cond.py
x = int(input("x を入力してください > "))
y = int(input("y を入力してください > "))

# (x も y も偶数)または(x も y も 3 の倍数)
if (x % 2 == 0 and y % 2 == 0) or (x % 3 == 0 and y % 3 == 0):
    print("条件に当てはまります")
else:
    print("当てはまりません")

%(余り)は第 3 章で習いました. x % 2 == 0 は「x は偶数」,x % 3 == 0 は「x は 3 の倍数」です. コンソールの入力行を 4 と 8,6 と 9, 5 と 7 に変えて,3 通りとも試してみてください.

もうひとつ覚えておくと得をするのが,not を内側に配る 書き換えです.not をかっこの中へ入れると, and と or が入れかわります.

この条件これと同じ意味
not (A and B)(not A) or (not B)
not (A or B)(not A) and (not B)

5.5.3 の入力チェックが,まさにこの関係でした. 「10 以上 200 以下ではない」(not (10 <= length <= 200))と, 「10 より小さいまたは 200 より大きい」 (length < 10 or length > 200)は,まったく同じ条件です. どちらで書いてもかまいませんが,読んで意味が分かるほうを選んでください.

or と and の取りちがえ よくある間違いが,「〜でない」を and でつなぐことです. 「1 でも 2 でもない」を kind != 1 and kind != 2 と書くのは正しく, kind != 1 or kind != 2 と書くといつでも成立してしまいます (kind が 1 なら 2 つめが成立,2 なら 1 つめが成立するからです). 上の表の 2 行目を使うと,not (kind == 1 or kind == 2) = kind != 1 and kind != 2 と確かめられます.
虫食い虫食い 5-F 乗り物に乗れるかどうか

遊園地の絶叫マシンに乗れるかどうかを判定します. 乗れるのは,「12 歳以下ではない」かつ「120cm 以下ではない」ときです. ____ に and・or・not のどれかを入れて,完成させてください.

fill6_ride.py
age = int(input("年齢を入力してください > "))
height = int(input("身長(cm)を入力してください > "))

# 「12 歳以下ではない」かつ「120cm 以下ではない」
if ____ (age <= 12) ____ ____ (height <= 120):
    print("乗ることができます")
else:
    print("乗ることができません")

5.6 条件の中に,また条件

if の中に,さらに if を書くことができます. これを入れ子(ネスト)といいます. 内側の if は,さらに 4 つ字下げします.

nest.py
n = int(input("整数を入力してください > "))

if n >= 1:
    print("1 以上です")
    if n <= 3:
        print("しかも 3 以下です")
    else:
        print("でも 4 以上です")
else:
    print("0 以下です")

print("おしまい")

字下げの深さが,そのまま入れ子の深さを表しています. どの else がどの if の相手なのかは, 字下げの位置がそろっているかどうかで決まります.

この例は,and を使って次のように書き換えられます.

入れ子を and で書き換える
if n >= 1 and n <= 3:
    print("1 以上 3 以下です")
深くしすぎない 入れ子は 2 段までにしておくと読みやすいです. 3 段,4 段と深くなってきたら, and でまとめられないか, elif で横に並べられないかを考えてみてください. 深い入れ子は,書いた本人にも読めなくなります.

5.6.1 入れ子で絵を選ぶ

nest_draw.py
from turtle import *

kind = int(input("1: 四角 2: 三角 > "))
big = int(input("1: 大きく 2: 小さく > "))

if big == 1:
    length = 160
else:
    length = 70

pensize(3)

if kind == 1:
    pencolor("navy")
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
    lt(90)
    fd(length)
    lt(90)
else:
    pencolor("crimson")
    fd(length)
    lt(120)
    fd(length)
    lt(120)
    fd(length)
    lt(120)

print(f"1 辺 {length} の図形を描きました")

ht()
done()

2 回の入力を変えると,4 とおりの絵が描けます. 条件を分けて書くことで,組み合わせが自然に作れました. もしこれを 1 つの if で書こうとすると, 4 つの枝それぞれに図形を描く命令を書くことになり,ずっと長くなります.

図 5.9 1 と 1
図 5.10 2 と 2

5.7 変数はどこから見えるか

変数には有効範囲(スコープ)という考え方があります. 「その名前がどこから使えるか」という範囲のことです. ここは思い違いの起きやすいところなので,落ち着いて読んでください.

5.7.1 if はスコープを作らない

Python では,if や else の字下げは スコープを作りません. if の中で作った変数は,if を抜けたあともそのまま使えます.

scope1.py
n = 5

if n > 3:
    message = "大きい"        # if の中で作った

print(message)                # if の外でも使える!
変数処理A(if の中)処理B(else の中)if を抜けたあと
z(if より前で作った)使える使える使える
x(if の中で作った)使えるまだ無い条件が成立していれば使える
y(else の中で作った)まだ無い使える条件が不成立だったら使える

「使えない」のではなく「まだ作られていない」という言い方になります. そこが大事なところです.

5.7.2 だから起きる事故

ときどきだけ落ちるプログラム 条件が成立しなかったとき,その変数は作られません. その状態で使おうとすると NameError になります. しかもある入力のときだけエラーになるので,たちが悪いです.
scope2.py
n = 1                         # ← 3 以下なので if は成立しない

if n > 3:
    message = "大きい"        # 実行されない = message は作られない

print(message)                # NameError: name 'message' is not defined

直し方は簡単です.if より前に,初期値を入れておくのです.

scope3.py
n = 1

message = "小さい"            # ← 先に初期値を入れておく

if n > 3:
    message = "大きい"        # 成立したときだけ上書きする

print(message)                # どちらの場合も動く
else を書けば安全 if / elif / else の すべての枝で変数に値を入れているなら,初期値は要りません. 5.4 節のグレード判定がそうでした(どの枝でも grade に値を入れています). else を書かないときほど危ないと覚えておいてください.
では Python のスコープの区切りは何か Python にもスコープはあります.ただし,区切りになるのは if や for ではなく関数です. def で作った関数の中で作った変数は,その関数の中だけで生きています. 関数は第 13 章で習いますので,そのときにあらためて説明します. 今のところは「if はスコープを作らない」とだけ覚えてください.

5.8 乱数と組み合わせる

5.8.1 おみくじ

前の章の乱数と,今回の条件分岐を組み合わせると,おみくじが作れます. 1 から 10 までの数をでたらめに選び,その数に応じて結果を変えます.

omikuji.py
import random
from turtle import *

number = random.randint(1, 10)     # 1 から 10 までのどれか
print(f"(引いた番号は {number} でした)")

if number == 1:
    result = "凶"
elif number <= 4:
    result = "小吉"
elif number <= 8:
    result = "中吉"
else:
    result = "大吉"

print(f"今日の運勢は「{result}」です")

# 画面にも大きく出す
ht()
pencolor("crimson")
pu()
goto(0, 60)
pd()
write(result, align="center", font=("Arial", 64, "bold"))

# 大吉のときだけ,お祝いの星を描く
if result == "大吉":
    pencolor("gold")
    pensize(4)
    pu()
    goto(-100, -60)
    pd()
    fd(200)
    rt(144)
    fd(200)
    rt(144)
    fd(200)
    rt(144)
    fd(200)
    rt(144)
    fd(200)
    rt(144)

done()
大吉
図 5.11 「大吉」が出たとき
中吉
図 5.12 「中吉」が出たとき(星は描かれない)

何度か実行してみてください.まれに「大吉」が出て,星が描かれます. 確率は 10 分の 2です(9 と 10 のとき).

elif の条件が短くて済む理由 number <= 4 という条件が「2・3・4」を意味するのは, その手前で number == 1 がすでに調べ終わっているからです. elif は「ここまでのどれにも当てはまらなかったうえで」 という意味を持っています. number >= 2 and number <= 4 と書かなくてよいのは,このためです.

5.8.2 じゃんけん — データのモデル化

コラム:グー・チョキ・パーをどう表すか じゃんけんをプログラムにしたいとき,最初にぶつかる問題があります. 「グー」「チョキ」「パー」を,コンピュータにどう覚えさせるかです. コンピュータは「グー」という概念を知りません.
  • グーを 1,チョキを 2,パーを 3 と決める
  • random.randint(1, 3) で手を選ぶ
  • if でその数を見て,対応する絵を描く
このように,現実のものごとをコンピュータが扱える形に置き換える作業を モデル化(データ構造の設計)といいます. プログラムを作るとき,コードを書く前に必ず通る作業です. 今回は「3 種類のものを 1・2・3 という数で表す」という,いちばん簡単なモデル化をしました.
janken.py
import random
from turtle import *

# グーを 1,チョキを 2,パーを 3 とする
hand = random.randint(1, 3)

pensize(8)
pencolor("darkslateblue")

if hand == 1:
    print("グー")
    dot(160)
elif hand == 2:
    print("チョキ")
    lt(60)
    fd(150)
    bk(150)
    rt(120)
    fd(150)
else:
    print("パー")
    lt(30)
    fd(150)
    bk(150)
    lt(30)
    fd(150)
    bk(150)
    lt(30)
    fd(150)
    bk(150)
    lt(30)
    fd(150)
    bk(150)
    lt(30)
    fd(150)
    bk(150)

ht()
done()
図 5.13 hand = 1 グー
図 5.14 hand = 2 チョキ
図 5.15 hand = 3 パー
ヒント 絵は思い切り簡単にしてあります. グーは点,チョキは 2 本の線,パーは 5 本の線です. 次の演習 5-4 では絵は描かず,勝ち負けを決めるロジック(条件分岐)だけを作ります.

5.9 この章で出てきた書き方

書き方意味
if 条件式:条件が成立したときだけ,字下げした部分を実行する
elif 条件式:ここまでが不成立で,この条件が成立したとき.いくつでも書ける
else:ここまでのどれも不成立だったとき.条件は書かない
字下げ(半角 4 つ)どこまでが if の中身かを表す
==等しい(イコール 2 つ).= は代入なので別物
!=等しくない
> <より大きい/より小さい
>= <=以上/以下(等しいときも成立)
andかつ(両方とも成立)
orまたは(どちらか一方でも成立)
not〜でない(成立・不成立をひっくり返す)
( )条件のかたまりを作る.not・and・or の順に計算されるので,迷ったら付ける
True False成立/不成立.bool 型.先頭だけ大文字
a <= x < b範囲のつなげ書き(Python だけの書き方)
pass何もしないと書く.ブロックを空にできないときに置く
random.randint(a, b)a 以上 b 以下の整数を 1 つ(前の章の復習)

演習

「▶ この演習を開く」で右側に読み込み,出発点のプログラムを 自分で発展させて作品にしてください. input() を使う演習にはコンソールの入力行に値が入っています. すべての枝を 1 回ずつ通して確かめてから仕上げてください.

全部の枝を通すこと 条件分岐のあるプログラムは,1 回実行しただけでは確かめたことになりません. elif が 5 本あるなら,入力を 5 通り変えて 5 回実行してください. これをテストといい,プロのプログラマも同じことをしています.
演習演習 5-1 図形屋さん

番号を入力すると,その図形を描く「図形屋さん」を作ります. 3 を入力したら 3 角形,4 なら 4 角形,5 なら 5 角形です. 図形を描く命令は,すでに全部書いてあります. あなたが書くのは,if の仕組み(条件分岐)だけです.

  1. 出発点を実行すると,3 つの図形が全部描かれてしまう.それぞれの図形の命令のまとまりの前に if・elif・else を書き,入力した番号の図形だけが描かれるようにする.
  2. if の次の行からは,4 つ字下げする.字下げした行だけが,その条件のときに実行される.
  3. まずは,番号は 3・4・5 のどれかが入力される前提で作ってよい.最後の 5 角形は,条件を書かずに else にしてもよい.
  4. これもやりましょう:3・4・5 以外(2 以下や 6 以上)が入力されたら,図形は描かずに「3・4・5 のどれかを入力してください」と表示する(or を使う.このとき 5 角形は else ではなく条件を書く必要があります).
  5. これもやりましょう:番号の次に1 辺の長さも input() で受け取り,その長さで図形を描く.コンソールの入力行には「3」「100」のように 2 行入れて試す(3 と 100 なら 1 辺 100 の 3 角形,5 と 60 なら 1 辺 60 の 5 角形).
ここがポイント 3 つの図形は,どれも描き終わると,出発したときと同じ位置・向きに戻ります. だから 3 つを続けて書いても,同じ場所から描き始められます. 入力に合わない図形が描かれてしまうときは,字下げがそろっているか確かめてください.
3 を入力したときの例(3 角形だけが描かれる)
評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. 3・4・5 を入力すると,その番号の図形だけが描かれる(3 通りとも確かめてある)
  2. if・elif・else の字下げがそろっている
  3. 3・4・5 以外(例:2 や 7)を入力すると,図形を描かずに注意が表示される(or を使っている)
  4. 2 つ目の入力で 1 辺の長さが決まる(3 と 100 で 1 辺 100 の 3 角形,5 と 60 で 1 辺 60 の 5 角形)

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 6 角形・8 角形など,選べる図形を増やす(注意を出す条件も合わせて直す)
  • 長さが 0 以下や 200 より大きいときも注意を出す(and・or を使う)
  • 図形ごとに色を変え,描いた図形の名前を write で画面にも書く

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

演習演習 5-2 おみくじ

乱数と条件分岐を使ったおみくじを作ります. 出発点は「大吉・中吉・小吉・凶」の 4 段階です.

  1. 「末吉」「大凶」を加えて6 段階にする.乱数は random.randint(1, 100) にして,それぞれの出る確率を下の表のとおりにする(合計 100 %).
  2. 結果に応じて描く絵を変える.少なくとも大吉なら星(1 辺 220 くらいの大きな星),大凶なら雨(ななめの線を 4 本以上)を描く.
  3. 結果に応じて文字の色と大きさを変える(6 段階すべてで色を変え,大吉と大凶は文字の大きさも変える.write(result, align="center", font=("Arial", 大きさ, "bold")) の大きさを変数にする).
  4. これもやりましょう:最初に名前を input() で受け取り,f 文字列で「かめさんの今日の運勢は「大吉」です(番号 95)」のように表示する.
番号(1〜100)結果確率
1〜5大凶5 %
6〜20凶15 %
21〜40末吉20 %
41〜65小吉25 %
66〜90中吉25 %
91〜100大吉10 %
確率の決め方 random.randint(1, 100) にすると, 確率を 1 % きざみで決められます. 「1〜5 なら大凶(5 %)」「6〜20 なら凶(15 %)」という具合です. elif は上から順に調べるので,number <= 5,number <= 20,… と 小さい順に並べれば,範囲の下の端は書かなくてすみます.

確かめるときは,number = random.randint(1, 100) のすぐ下に number = 3 や number = 95 のような行を一時的に足すと, 決まった結果を出せます.6 段階すべてを確かめたら,その行は消してください.

評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. random.randint(1, 100) と表の範囲で 6 段階に分かれている(境目 5・6・20・21・…・90・91 も正しい)
  2. 大吉なら星,大凶なら雨(ななめの線 4 本以上)が描かれる
  3. 6 段階すべてで文字の色が違い,大吉と大凶は文字の大きさも違う
  4. 入力した名前が f 文字列で「○○さんの今日の運勢は「…」です(番号 …)」と表示される

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 6 段階すべてで違う絵を描く(中吉は小さな星 2 つ,凶はくもり空,など)
  • 名前の入力が空のとき(何も入力しなかったとき)は「ななしさん」と表示する
  • 運勢ごとに「ラッキーカラー」や「ひとこと」も表示する

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

演習演習 5-3 評点グレード変換

評点を入力すると,合格か不合格かを判定し, 成績のグレード(A・B・C・D・F)を表示するプログラムです. 評点 60 点以上を合格とします. 出発点では,グレードだけが表示されます. グレードと GP(グレードポイント)の基準は次の表のとおりです.

評点グレードGP合否星の数
90 点以上(100 点まで)A(秀)4合格5 個
80〜89 点B(優)3合格4 個
70〜79 点C(良)2合格3 個
60〜69 点D(可)1合格1 個
60 点未満(0 点まで)F(不可)0不合格0 個
  1. 合格・不合格を判定して表示する(60 点以上なら「合格」,60 点未満なら「不合格」).
  2. 0 未満や 100 より大きい評点が入力されたら,or を使ってはじき,「0 から 100 の間で入力してください」と注意を表示する(このときはグレードも GP も表示しない).
  3. グレードだけでなく,表の GP も表示する(85 点なら「評点 85 点 → 合格(グレード「B」/ GP 3)」).
  4. グレードに応じてメッセージを変える(5 つのグレードすべてで違うメッセージ.例:A「たいへんよくできました」,F「来年またがんばりましょう」).
  5. これもやりましょう:グレードに応じて,タートルで星を描く(表のとおり A なら 5 個,B 4 個,C 3 個,D 1 個,F 0 個).星は 1 辺 50 で,fd(50) と rt(144) を 5 回くり返せば 1 個描けます.描き始めの位置は左から順に goto(-220, -120)・(-125, -120)・(-30, -120)・(65, -120)・(160, -120) とする.for はまだ使えないので,「何点以上なら何個目の星を描くか」を考えてif を並べてください.

確かめるときの入力例:95(A・星 5),85(B・星 4), 72(C・星 3),60(D・星 1),59(F・不合格・星なし), -5 と 120(注意だけ). 境目の 90・80・70・60 も必ず試してください.

評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. 表の基準どおりにグレードと GP が表示される(95・85・72・60・59 で A4・B3・C2・D1・F0)
  2. 合格・不合格が正しく表示される(60 点は合格,59 点は不合格)
  3. 0 未満・100 より大きい評点では,or の条件で注意だけが表示される
  4. 5 つのグレードで違うメッセージが表示される
  5. 星の数がグレードに合っている(A 5・B 4・C 3・D 1・F 0)

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 評点を 2 科目ぶん受け取り,平均点でグレードを出す
  • グレードごとに星の色や,write で書く文字の色を変える
  • 合格・不合格も write で画面に表示し,不合格のときは赤い字にする

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

演習演習 5-4 じゃんけん

コンピュータがじゃんけんの手を出すプログラムです. 今回は絵は描きません. ロジック(条件分岐)だけで作り, あなたとコンピュータが対戦できるようにしてください.

  1. 自分の手も入力してもらう(1:グー 2:チョキ 3:パー).
  2. if と and で勝敗を判定する(グーはチョキに勝つ,など).
  3. あいこのときは「あいこです」と表示する.勝ち・負けも「あなたの勝ち」「あなたの負け」と表示し,その前に「あなたはグー,コンピュータはチョキ」のように両方の手を名前で表示する.
  4. これもやりましょう:1・2・3 以外が入力されたら,勝負をせずに「1・2・3 のどれかを入力してください」と表示する(or か not を使う).
勝敗の判定 勝敗の判定は,全部で 9 とおりしかありません. if と elif を並べて書けば必ず書けます. 短く書く方法もありますが(あいこ・勝ち・負けを引き算の余りで求める), まずは素直に 9 とおり並べてみてください.

確かめるときは,コンピュータの手を決めた行のすぐ下に computer = 2 のような行を 一時的に足すと,決まった手で試せます. 自分の手 1・2・3 とコンピュータの手 1・2・3 の 9 とおりと,0 や 4 の入力を確かめたら, その行は消してください.

評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. 自分の手を入力でき,両方の手が名前(グー・チョキ・パー)で表示される
  2. 9 とおりすべてで勝ち・負け・あいこが正しく判定される(and を使っている)
  3. 1・2・3 以外の入力では,勝負をせずに注意だけが表示される

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 勝敗の判定を「(自分 − 相手) を 3 で割った余り」で短く書き,9 とおり並べた版と結果が同じか確かめる
  • あいこ・勝ち・負けで違う絵や文字を write で画面に出す
  • コンピュータの手の出やすさを変える(random.randint(1, 10) で 1〜4 はグー,5〜8 はチョキ,9・10 はパー,など)

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

演習演習 5-5 体型評価プログラム

身長と体重を入力すると,BMI 指数を計算し, その値から体型を判定するプログラムです. ただし出発点の BMI の計算式には間違いがあります. まず式の間違いを見つけて修正してから,判定を作ってください.

BMI の求め方(これが正しい式です) BMI(体格指数)は,体重と身長から体格をはかる数です. BMI = 体重(kg)÷ [身長(m)× 身長(m)]で求めます. 身長はメートルで計算します. cm で入力させるなら,100 で割って m に直してから使います.
例:身長 170 cm(=1.7 m),体重 62 kg のとき, 62 ÷ (1.7 × 1.7)= 21.4532… となり,小数第 2 位を四捨五入すると 21.5 です.
出発点のプログラムに 170 と 62 を入力すると, BMI が体重とほぼ同じ値(61.99999999999999)になってしまいます. 21.5 前後になるように,式を直してください.
  • 判定は,18.5 未満=やせ,18.5 以上 25 未満=標準,25 以上 35 未満=肥満,35 以上=高度肥満.
  • BMI は小数第 2 位で四捨五入して表示する(前の章で習った int(x * 10 + 0.5) / 10 を使う).
  • 判定は,四捨五入したあとの BMI で行う.
  • 始めと終わりに「開始しました」「終了しました」と表示する.
  • 身長か体重が 0 以下なら,計算せずに「身長と体重は 0 より大きい値を入力してください」と表示する(下の注意を参照).
  • これもやりましょう:判定に応じてメッセージを変え(4 つの体型すべてで違うメッセージ),タートル画面に BMI と体型を write で 2 行に表示する.文字の色は体型で変える(やせ "blue",標準 "green",肥満 "orange",高度肥満 "red").
身長(cm)体重(kg)BMI(四捨五入後)体型
1705017.3やせ
1706221.5標準
1607027.3肥満
1609537.1高度肥満
062(計算しない)注意を表示
0 で割らないように 身長を 0 と入力されると,0 で割ることになり ZeroDivisionError で止まります. if を使って,計算する前にはじいてください.
評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. BMI の式が直され,小数第 2 位で四捨五入した値が表示される(170・62 で 21.5)
  2. 表の 4 つの入力例で,体型が正しく判定される(やせ・標準・肥満・高度肥満)
  3. 身長か体重が 0 以下のときは計算せずに注意が表示され,エラーで止まらない
  4. 「開始しました」「終了しました」が表示される
  5. 体型ごとに違うメッセージが出て,画面に BMI と体型が指定の色で表示される

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 年齢も聞き,18 歳未満なら「この判定は大人向けです」と添えるなど,判定の説明を工夫する
  • 標準体重(身長(m)× 身長(m)× 22)を計算し,あと何 kg で標準体重かを表示する
  • 体型に応じて,画面に簡単な絵(人の形や体重計など)を描き分ける

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

自由演習 5-6 自由制作:判断するプログラム

条件分岐を使って,自由に作品を作ってください. 状況を見て動きが変わることが,今回の作品の条件です.

  • if を3 か所以上使うこと(elif も 1 つと数えてよい)
  • else を1 回以上使うこと
  • and・or・not のどれかを1 回以上使うこと
  • input() か random.randint() で,実行するたびに結果が変わるようにすること
  • 先頭のコメントに題名・氏名・日付を書くこと
  • すべての枝を 1 回ずつ通して確かめてから仕上げること
題材のヒント 題材に迷ったら:西暦を入力すると和暦(令和・平成・昭和)に変換するプログラム, 月を入力すると季節と,季節に応じた絵を描くプログラム, 性格診断(いくつか質問して点数を足し,点数で結果を分ける), 自動販売機(金額と商品番号を入力して,買えるかどうか判定する), 信号機(乱数で赤・青・黄を選んで描く),などはいかがでしょうか.
評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. if を 3 か所以上(elif を含めてよい),else を 1 回以上使っている
  2. and・or・not のどれかを 1 回以上使っている
  3. input() か random.randint() で,実行するたびに結果が変わる
  4. すべての枝を通して確かめてあり,先頭のコメントに題名・氏名・日付がある

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 条件の中に条件を入れる(入れ子)など,判断の流れに工夫がある
  • おかしな入力(範囲外の数など)をはじいて注意を出す
  • 判断の結果を絵や画面の文字でも分かりやすく見せる

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

まとめ

  • if 条件式: と書き,次の行から4 つ字下げする.コロンと字下げがセットでブロックを作る.
  • 条件式は == != < <= > >= で書き,結果は True か False(bool 型)になる.
  • == は比べる,= は入れる.まったく別物.
  • else で 2 つに,elif でいくつにも分けられる.elif は上から順に調べ,最初に成立した 1 つだけを実行する.だからきびしい条件から先に書く.
  • and(かつ)・or(または)・not(〜でない)で条件を組み合わせる.
  • 計算の順番は not → and → or.かたまりはかっこで囲む.not (A and B) は (not A) or (not B) と同じ意味になる.
  • Python では if はスコープを作らない.if の中で作った変数も外から見えるが,条件が不成立なら作られないので NameError に注意.先に初期値を入れておくか,すべての枝で値を入れる.
  • 乱数と条件分岐を組み合わせると,おみくじやじゃんけんが作れる.現実のものごとを数で表すことをモデル化という.
  • 条件分岐のあるプログラムは,すべての枝を通して確かめる.

次の回では,繰り返しを習います. for を使うと,fd と rt を 10 回書いていた正十角形が, たった 3 行で書けるようになります. 第 2 章と第 3 章で「面倒だ」と感じたことが,いっぺんに解決します.