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

Python の大事な文法

文法編の最後.ここまでを見わたして,足りないところを埋めます.

文法編の最後の章です.第 2 章でかめに fd(100) と命令したところから始まって, 変数・条件・繰り返し・関数・リスト・辞書と,ずいぶん遠くまで来ました. もう「やりたいことを手順に分解して,プログラムとして書く」ことが一通りできます.

今回は,ここまでの総まとめとして Python の文法を見わたします. ここまでは,その章に必要な分だけを説明してきました. 第 12 章で駆け足で見た break や and・or は,ここで整理し直します.

そのうえで,まだ説明していない便利なもの— 空のリストや 0 を条件に使う書き方,文字列の加工,書式をそろえた表示, None の扱い,入力の失敗への備え—を加えます. どれも知っていれば,これから書くプログラムがぐっと楽になるものばかりです.

各項目は短い例と,その場で動かせるコードで進めます. 長い理屈は書きません.実際に動かして,手ざわりを確かめてください. 最後に,第 21 章からの設計編で学ぶことと, この教材の外で学ぶことを挙げて,道しるべを置きます.

この章でできるようになること
  • break・continue で繰り返しを制御できる
  • 何回で終わるか分からない繰り返しを,while か「上限つきの for と break」で書ける
  • not・and・or で条件を組み立てられる
  • 空のリスト・空の文字列・0 が偽になることを知り,if a: の意味がわかる
  • in・not in と,0 <= x < 100 のような連鎖比較が書ける
  • 文字列を切る・つなぐ・置きかえる・区切る,といった加工ができる
  • f-string で,小数のけた数や幅をそろえて表示できる
  • a, b = b, a と,関数から複数の値を返す書き方が使える
  • None と is None の意味がわかる
  • try/except で,入力の失敗に備えられる
  • import の 3 つの書き方を使い分けられる
  • この教材で扱わなかったことを知り,次に何を学べばよいかがわかる

20.1 繰り返しの制御 — break と continue(第 12 章の復習)

break と continue は,第 12 章の 12.8 節で習いました. 第 17 章の線形探索でも,「見つかったら,もう探さなくてよい」ところで break を使いました.違いを表で確かめておきます.

breakcontinue
何をする繰り返しを終わらせるその回の残りを飛ばして次の回へ進む
そのあとfor の次の行へfor の先頭へ戻る
よく使う場面探しものが見つかった/条件を満たしたのでもう用がないこの値は対象外なので飛ばしたい
break_continue.py
# break:4 になったら繰り返しをやめる
for i in range(10):
    if i == 4:
        break
    print("break の例", i)

print("---")

# continue:偶数の回は飛ばす
for i in range(6):
    if i % 2 == 0:
        continue
    print("continue の例", i)

print("---")

# 実用:リストから探して,見つかったらやめる
a = [14, 8, 23, 5, 42, 16]
sagasu = 23

basho = -1
for i, x in enumerate(a):
    print(i, "番目の", x, "とくらべる")
    if x == sagasu:
        basho = i
        break

if basho >= 0:
    print(sagasu, "は", basho, "番目にありました")
else:
    print(sagasu, "はありませんでした")
効くのは内側 1 つだけ break と continue が効くのは, いちばん内側の繰り返し 1 つだけです. 二重の for の内側で break しても, 外側の for は続きます.

20.1.1 何回で終わるかわからないとき

for は回数が決まっているときの道具でした. ところが,世の中には「何回やれば終わるのか,やってみないと分からない」仕事があります. たとえば「1 円が毎日 2 倍になるとして,1 億円を超えるのは何日目か」. 答えが分かっていれば for で書けますが, 答えを知りたくて計算しているのですから,回数は書けません.

書き方は 2 つあります. 条件で回す while(第 17 章で, カードを 1 枚ずつ移すときに使いました)と, 多めの回数で回しておいて break で抜ける for です.

baibai.py
# 1 円が毎日 2 倍になる.1 億円を超えるのは何日目?

# 書き方 A:while で,条件が成り立つあいだ回す
okane = 1
hi = 0

while okane <= 100000000:
    hi = hi + 1
    okane = okane * 2

print("A:", hi, "日目に", okane, "円")

print("---")

# 書き方 B:多めに回しておいて,超えたら break
okane = 1

for hi in range(1, 101):        # 100 日もあれば足りるだろう,という上限
    okane = okane * 2
    if okane > 100000000:
        print("B:", hi, "日目に", okane, "円")
        break

どちらでも同じ答えが出ます. while のほうが素直ですが, 条件の書き方をまちがえると終わらなくなるのが怖いところです. for と break の組み合わせなら, たとえ break の条件をまちがえても 上限の回数で必ず止まります.

while True: は使わない ほかの入門書では,ここで while True:(いつまでも回す)と書いて break で抜ける,というやり方を教えていることがあります. この教材ではその書き方は使えません. プログラムはブラウザの中で動いているので,止まらなくなると画面ごと固まってしまいます. 必ず終わる条件を書くか, for に多めの上限を付けて break するか, どちらかにしてください.

タートルでも同じことが起きます. 「画面からはみ出すまで進み続ける」のは,何歩で終わるか分からない仕事です. xcor()・ycor() でいまの場所を自分で確かめて, はしまで来たら break で止めます.

spiral_break.py
from turtle import *

ht()
speed(0)
pensize(3)
pencolor("#3498db")

nagasa = 6

for i in range(60):          # 60 回は「多めに見積もった上限」
    if abs(xcor()) > 250 or abs(ycor()) > 180:
        print(i, "歩目で画面のはしに来たので,ここでやめます")
        break
    fd(nagasa)
    lt(144)                  # 144 度ずつ曲がると星のような形になる
    nagasa = nagasa * 1.3    # 1 歩ごとに 1.3 倍ずつ長くなる

print("止めなければ,次は", round(nagasa), "も進むところでした")

done()
図 20.1 1 歩ごとに 1.3 倍ずつ長くなるかめ.何歩で画面のはしに届くかは分からないので,上限つきの for と break で止めている.
abs() — 絶対値 abs(x) は絶対値,つまり符号を取り払った値です. abs(-250) は 250 になります. abs(xcor()) > 250 と書けば, 「右へ行きすぎ」と「左へ行きすぎ」を1 つの条件でまとめて調べられます. nagasa の増える割合(1.3)を変えると, 止まるまでの歩数が変わります.試してみてください.

20.2 真偽値と論理演算子

if のうしろに書く条件は,最後には True(真)か False(偽)の どちらかになります.この 2 つの値を真偽値といいます.

20.2.1 not・and・or — 条件を組み立てる(第 12 章の復習)

書き方意味使いどころの例
not AA をひっくり返す.not True は False「ゲーム中でなければ操作を受け付けない」
A and B両方とも成り立つとき「18 歳以上かつ学生」
A or Bどちらか一方でも成り立つとき「左の壁または右の壁に当たった」
かっこを惜しまない and と or が混ざるときは, かっこを付けて意図をはっきりさせてください. a or b and c は a or (b and c) の意味ですが, 読む人(とくに数日後の自分)は迷います. 迷ったらかっこ.付けすぎて悪いことは何もありません.

20.2.2 空のリスト・空の文字列・0 は「偽」

Python では,True・False 以外のものも if の条件に書けます. そのとき「空っぽ」「ゼロ」は偽として扱われます.

値真偽おぼえ方
0・0.0偽ゼロは偽
0 以外の数真
""(空の文字列)偽空っぽは偽
"あ" など中身のある文字列真
[]・{}・set()偽空の入れ物も空っぽ
中身のあるリスト・辞書・集合真
None偽「何も無い」も偽

これを知っていると,条件が短く書けます.

空かどうかの書き方
# 長い書き方
if len(a) > 0:
    print("中身があります")

# 短い書き方(同じ意味)
if a:
    print("中身があります")

# 空かどうか
if not a:
    print("からっぽです")
短ければよいわけではない ただし,数を調べたいときは省略しないほうがよいことが多いです. if kazu: は「0 でなければ」という意味になりますが, if kazu > 0: と書いたほうが,読む人には意図が伝わります. 短さより,読んだときに意味が分かることを優先してください.

20.2.3 in / not in と,連鎖比較

in は「入っているか」を調べる書き方でした. 否定は not in と書きます(not x in a ではありません).

もう 1 つ,Python ならではの便利な書き方があります. 比較を 2 つつなげて書けるのです. 数学と同じ見た目になるので,範囲の判定がとても読みやすくなります.

書き方意味他の言語では
0 <= x < 100x が 0 以上 100 未満0 <= x and x < 100 と 2 つに分けて書く
a < b < ca より b が大きく,b より c が大きい同じく 2 つに分ける
x in a / x not in a入っている/入っていない—
logic.py
# not / and / or
playing = False
if not playing:
    print("ゲームは止まっています")

x = 120
y = 40
if x > 100 and y > 30:
    print("and:2 つとも成り立つ")
if x > 500 or y > 30:
    print("or:どちらか一方でも成り立つ")

print("---")

# 空っぽは偽
a = []
b = [1, 2, 3]
namae = ""

if not a:
    print("a はからっぽ")
if b:
    print("b には", len(b), "個入っている")
if not namae:
    print("名前が入力されていません")

print(bool(0), bool(5), bool(""), bool("あ"), bool([]), bool([0]))

print("---")

# in / not in
kudamono = ["りんご", "みかん"]
print("りんご" in kudamono)
print("すいか" not in kudamono)
print("と" in "たーとる")          # 文字列の中にもある

print("---")

# 連鎖比較
ten = 85
if 80 <= ten < 90:
    print("A 判定")

for t in [-5, 0, 50, 100, 120]:
    if 0 <= t <= 100:
        print(t, "は正しい点数")
    else:
        print(t, "はありえない点数")
虫食い虫食い 20-A 入場の受付をする

年齢・名前・持ち物から,入場の受付をします. ____ を埋めてください. 範囲は連鎖比較で,「空かどうか」は真偽値の省略で, 「入っていないか」は not in で書きます.

fill20_logic.py
# 入場の受付

nenrei = 17
namae = ""                       # 受付で書く名前(まだ書いていない)
motimono = ["かばん", "みずとう", "かさ"]
kinshi = ["はもの", "かさ"]

# (1) 年齢が 6 以上 18 未満なら「学生料金」(連鎖比較で書く)
if ____ <= nenrei ____ 18:
    print("学生料金です")
else:
    print("おとな料金です")

# (2) 名前が空の文字列なら,書いてもらう(空の文字列は偽)
if ____ namae:
    print("名前を書いてください")

# (3) 禁止されていない持ち物だけを集める
motikomu = [m for m in motimono if m ____ kinshi]
print("持ちこめるもの:", motikomu)

# (4) 預ける物があれば知らせる(空でないリストは真)
azukeru = [m for m in motimono if m in kinshi]
if ____:
    print(azukeru, "は預けてください")

# (5) 持ち物がからっぽなら,そう言う
if not motimono:
    print("手ぶらですね")

20.3 文字列をあつかう

第 9 章の CUI プログラムで input() を使いました. 受け取るのはいつも文字列です. 文字列を切ったり,つないだり,区切ったりできると,作れるものが広がります.

20.3.1 文字列はリストに似ている

文字列は文字が並んだものなので, リストと同じ感覚であつかえます. len も,添字も,スライスも,in もそのまま使えます.

書き方意味
len(s)文字数
s[0] / s[-1]最初の文字/最後の文字
s[0:3] / s[::-1]先頭 3 文字/逆順(第 19 章のスライス)
s + tつなぐ
s * 33 回くり返す."-" * 30 は区切り線に便利
"る" in sその文字(や語)が入っているか
str(n) / int(s) / float(s)数と文字列を行き来する
文字列は変えられない 文字列はあとから変えられません(タプルと同じです). s[0] = "あ" はエラーになります. 変えたいときは,s = s.replace(…) のように 新しい文字列を作って入れ直します.

20.3.2 よく使うメソッド

書き方すること例
s.upper() / s.lower()大文字に/小文字に"abc".upper() → "ABC"
s.strip()前後の空白や改行を取り除く入力の後始末にほぼ必須
s.split(区切り)区切ってリストにする"a,b,c".split(",") → ["a", "b", "c"]
区切り.join(リスト)リストをつなげて文字列にする",".join(["a", "b"]) → "a,b"
s.replace(前, 後)置きかえる(全部)"あかあか".replace("あか", "しろ")
s.find(x)x が何番目にあるか.無ければ -1"たーとる".find("と") → 2
s.count(x)x がいくつ入っているか—
s.startswith(x)x で始まるか—
string.py
s = "たーとるぐらふぃっくす"

print(len(s))
print(s[0], s[-1])
print(s[0:3])
print(s[::-1])
print(s + "!")
print("-" * 24)
print("る" in s)

print("---")

t = "  Hello, Turtle World  "
print("[" + t + "]")
print("[" + t.strip() + "]")          # 前後の空白を取る
print(t.strip().upper())
print(t.strip().lower())
print(t.strip().replace("Turtle", "Python"))

print("---")

# 区切る → リスト/つなぐ → 文字列
gyo = "あかり,けんた,ゆうき"
namae = gyo.split(",")
print(namae)
print(" と ".join(namae))
print("/".join(namae))

print("---")

print("たーとる".find("と"))     # 2 番目にある
print("たーとる".find("ね"))     # 無いので -1
print("あかあおあか".count("あか"))
print("turtle.py".startswith("turtle"))

# 数と文字列の行き来
print(int("42") + 1)
print(str(42) + "点")
print(float("3.5") * 2)

20.3.3 f-string — 表示をきれいにそろえる

第 3 章で,print("平均は", heikin, "点") のようにカンマで区切って並べるかわりに, f-string(エフストリング)で文字列の中に { } で値を埋め込めることを習いました. この節では,その { } の中で書式を指定する方法を加えます.

f-string
namae = "あかり"
ten = 87.5

# これまでの書き方
print(namae, "さんは", ten, "点です")

# f-string(先頭に f を付けて,{ } の中に変数を書く)
print(f"{namae}さんは{ten}点です")

本当に便利なのは,{ } の中でけた数や幅を指定できることです. {値:書式} の形で書きます.

書き方意味結果の例
{x:.2f}小数点以下 2 けたに丸める3.14
{x:.0f}小数点以下を出さない3
{x:5}5 文字ぶんの幅を取る(数は右寄せ)   42
{x:>8} / {x:<8} / {x:^8}右寄せ/左寄せ/中央ぞろえ—
{n:03d}0 を詰めて 3 けたにする007
{n:,}3 けたごとにカンマを入れる1,234,567
{n:>8,} / {x:,.1f}幅・寄せ方・カンマ・けた数は組み合わせられる   1,234
{a + b}中で計算もできる—
fstring.py
namae = "あかり"
ten = 87.5
kazu = 1234567

print(f"{namae}さんは {ten} 点です")
print(f"1 + 2 = {1 + 2}")

print("---")

# 小数のけた数
heikin = 72.66666
print(f"平均は {heikin} 点")
print(f"平均は {heikin:.2f} 点")
print(f"平均は {heikin:.1f} 点")
print(f"平均は {heikin:.0f} 点")

print("---")

# けたをそろえる(表になる)
seiseki = [("あかり", 78, 158.2), ("けんた", 92, 172.5),
           ("ゆうき", 6, 165.0), ("みさき", 100, 149.8)]

print(f"{'名前':<8}{'点数':>6}{'身長':>9}")
print("-" * 26)
for n, t, h in seiseki:
    print(f"{n:<8}{t:>6}{h:>9.1f}")

print("---")

print(f"{7:03d} 番")
print(f"{kazu:,} 円")
print(f"[{'あか':>6}] [{'あか':<6}] [{'あか':^6}]")
日本語の幅 幅の指定は文字数で数えます. 日本語は 1 文字が半角 2 文字ぶんの幅で表示されるので, 日本語と半角が混ざると,画面の上ではきれいにそろわないことがあります. 数字だけの表なら,きちんとそろいます.

タートルの write とも相性がよい書き方です. str() や + を並べずに済むので, 画面に文字を書くプログラムがぐっと読みやすくなります.

write_fstring.py
from turtle import *

ht()

seiseki = [("あかり", 78), ("けんた", 92), ("ゆうき", 61), ("みさき", 55)]

ten = [t for n, t in seiseki]
heikin = sum(ten) / len(ten)

pu()
goto(-240, 160)
pencolor("black")
write(f"{len(seiseki)} 人の成績(平均 {heikin:.1f} 点)",
      font=("Arial", 20, "normal"))

y = 100
for jun, kumi in enumerate(seiseki):
    namae = kumi[0]
    t = kumi[1]
    pu()
    goto(-240, y)
    if t >= 60:
        pencolor("navy")
    else:
        pencolor("crimson")
    write(f"{jun + 1} 位 {namae}", font=("Arial", 20, "normal"))
    goto(80, y)
    write(f"{t:>3} 点", font=("Arial", 20, "normal"))
    y = y - 55

done()
4 人の成績(平均 71.5 点)1 位 あかり 78 点2 位 けんた 92 点3 位 ゆうき 61 点4 位 みさき 55 点
図 20.2 f-string で書式をそろえて write したもの.
虫食い虫食い 20-B 成績表をきれいに表示する

入力された名前と点数から,成績表を作って画面に描きます. ____ を埋めてください. 文字列を区切るところと,f-string の書式がポイントです.

fill20_fstring.py
from turtle import *

ht()

# 「名前:点数」をカンマ区切りで受け取る
gyo = input("例)あかり:78,けんた:92 のように入力:")

# (1) カンマで区切ってリストにする
kumi = gyo.____(",")
print(kumi)

seiseki = []
for k in kumi:
    # (2) コロンで区切って,名前と点数に分ける
    namae, ten = k.____(":")
    # (3) 点数は文字列なので,数に直す
    seiseki.append((namae.strip(), ____(ten)))

print(seiseki)

# (4) 平均を小数点以下 1 けたで表示する
ten = [t for n, t in seiseki]
heikin = sum(ten) / len(ten)
print(f"平均は {heikin:____} 点")

# (5) 画面に書く
y = 130
for namae, t in seiseki:
    pu()
    goto(-200, y)
    write(f"{namae} {t:>4} 点", font=("Arial", 22, "normal"))
    y = y - 55

pu()
goto(-200, y - 20)
write(f"平均 {heikin:.1f} 点", font=("Arial", 22, "normal"))

done()

20.4 値のやりとり — 複数代入・複数の戻り値・None

20.4.1 複数代入 — 一度に 2 つ入れる

Python では,カンマで並べて一度に代入できます. 第 17 章で使った a, b = b, a(入れ替え)が代表です.

複数代入
x, y = 100, 50          # 一度に 2 つ
a, b = b, a             # 入れ替え.作業用の変数が要らない
namae, ten = ("あかり", 78)   # タプルをほどく
なぜ入れ替わるのか a, b = b, a がうまくいくのは, 右側を先に全部計算してから左側へ入れるからです. a = b と b = a を 2 行に分けて書くと, 1 行目で a の元の値が消えてしまい,入れ替わりません.

20.4.2 関数から 2 つ以上の値を返す

第 14 章で return を習いました. じつはカンマで並べれば,いくつでも返せます. 返ってくるのはタプル(第 19 章)なので, 受け取るときも複数代入でほどけます.

multi_return.py
def saidai_saisho(a):
    """最大値と最小値を両方返す"""
    return max(a), min(a)


def wa_to_sa(x, y):
    return x + y, x - y


ten = [72, 95, 61, 88, 40]

ue, shita = saidai_saisho(ten)
print("最高", ue, " 最低", shita)

wa, sa = wa_to_sa(10, 4)
print("和", wa, " 差", sa)

# 受け取らずにそのまま見ると,タプルになっている
print(saidai_saisho(ten))

print("---")

# 複数代入・入れ替え
x, y = 100, 50
print(x, y)
x, y = y, x
print(x, y)

20.4.3 None — 「まだ何も無い」を表す値

None は,「値が無い」ことを表す特別な値です. 0 でも空文字列でもありません.「まだ決まっていない」という印です.

  • return を書かない関数は,None を返します
  • d.get(k) は,キーが無ければ None を返します(第 18 章)
  • a.sort() は None を返します.b = a.sort() と書いて失敗するのはこのためです(第 17 章)

None かどうかを調べるときは, == None ではなく is None と書きます. 「同じ値か」ではなく「まさにそれか」を聞いているからです.

is None / is not None
kotae = None

if kotae is None:
    print("まだ答えが決まっていません")

if kotae is not None:
    print("答えは", kotae)
偽と None は違う None は偽として扱われるので if not kotae: とも書けますが, 0 や空文字列も偽なので,区別が付きません. 「0 が入っているのか,まだ何も入っていないのか」を分けたいときは, 必ず is None を使ってください.
虫食い虫食い 20-C 欠席と 0 点を区別する

点数のリストに,欠席の人の None が混じっています. 欠席(None)と 0 点を区別して集計してください. ____ を埋めてください. None かどうかは is で調べ, 「空かどうか」は真偽値の省略(20.2.2 節)で書きます.

fill20_none.py
# 欠席(None)と 0 点を区別して集計する

namae = ["あかり", "けんた", "ゆうき", "みさき", "そうた"]
ten = [65, None, 92, 0, None]      # None は欠席,0 は 0 点

# (1) 欠席した人の名前を集める
kesseki = []
for n, t in zip(namae, ten):
    if t ____ None:
        kesseki.append(n)
print("欠席:", kesseki)

# (2) 受験した人の点数だけを集める(0 点の人も入れる)
juken = [t for t in ten if t ____ None]
print("受験者の点数:", juken)

# (3) 受験者が 1 人でもいれば平均を出す(空のリストは偽)
if ____:
    print(f"{len(juken)} 人の平均は {sum(juken) / len(juken):.1f} 点")
else:
    print("受験者がいません")

# (4) 欠席者がいなければ,そう言う
if ____ kesseki:
    print("全員受験しました")

20.5 失敗に備える — try と except

int(input()) は,数を入力してもらう定番の書き方でした. しかし利用者が「ごじゅう」と打ったら,どうなるでしょうか.

文字を入れられると落ちる
n = int(input("数を入れてください:"))

ValueError が出て,プログラムはそこで止まります. このように,実行中に起きる異常を例外(れいがい)といいます. 例外が起きても止まらないようにする書き方が try/except です.

try / except の形
try:
    あぶないかもしれない処理
except 例外の種類:
    失敗したときにやること

try: の中で例外が起きると,そこで中断して except: の中へ飛びます.起きなければ except は素通りします.

例外の名前起きる場面
ValueErrorint("abc") のように,形が合わない値を渡したとき
ZeroDivisionError0 で割ったとき
IndexErrora[10] のように,無い番号を指したとき
KeyError辞書に無いキーを d[k] で引いたとき
TypeError"a" + 1 のように,種類の合わないものを混ぜたとき
NameError無い名前を使ったとき(打ち間違いが多い)
try_input.py
# 数を 3 回まで入力し直せるようにする

n = None

for i in range(3):
    kotae = input("数を入れてください:")
    try:
        n = int(kotae)
        break                       # うまくいったので繰り返しをやめる
    except ValueError:
        print(f"「{kotae}」は数ではありません.あと {2 - i} 回")

if n is None:
    print("数が受け取れませんでした.0 として続けます")
    n = 0

print(f"{n} の 2 倍は {n * 2} です")

# 0 で割る失敗にも備える
try:
    print(100 / n)
except ZeroDivisionError:
    print("0 では割れません")
except: だけで受けない except: と種類を書かずに全部受け止めることもできますが, やめてください. 打ち間違いによる NameError まで握りつぶしてしまい, 「なぜか動かないが,エラーも出ない」という最悪の状態になります. 受け止める例外の種類は必ず書く.
try の出番 例外は「使わずに済むならそのほうがよい」ものです. d.get(k, 0) や if k in d: で防げるなら,そちらを使ってください. try の出番は,防ぎようがない失敗— 人間の入力,ファイルの読み込み,通信—に備えるときです.
虫食い虫食い 20-D 安全な BMI 計算

身長と体重を入力して BMI を計算します. 数でないものを入れられても止まらないようにしてください. ____ を埋めてください.

fill20_bmi.py
# 安全な BMI 計算

shincho = None
taiju = None

# (1) 身長(cm)
s = input("身長を cm で入れてください:")
____:
    shincho = float(s) / 100
____ ValueError:
    print(f"「{s}」は数ではありません")

# (2) 体重(kg)
t = input("体重を kg で入れてください:")
try:
    taiju = float(t)
except ____:
    print(f"「{t}」は数ではありません")

# (3) どちらかが受け取れていなければ,ここで終わる
if shincho ____ None or taiju is None:
    print("計算できませんでした")
else:
    bmi = taiju / (shincho * shincho)
    # (4) 小数点以下 1 けたで表示する
    print(f"BMI は {bmi:____} です")
    if bmi < 18.5:
        print("やせ型です")
    elif ____ <= bmi < 25:
        print("標準です")
    else:
        print("肥満型です")

20.6 import の 3 つの書き方

print や len や sorted は, 何も書かなくても使えました(組み込み関数といいます). 一方,random.randint のように 使う前に道具箱を開けなければならないものがあります. これが標準ライブラリで,Python には 200 以上の箱が付いてきます.

道具箱よく使うもの何に使うか
randomrandint(a, b)・choice(a)・shuffle(a)・seed(n)でたらめな数や選択.第 3 章から使っています
mathsqrt(x)・pi・sin(x)・cos(x)・radians(d)平方根や三角関数.斜めの長さや円の計算
timetime()いまの時刻を秒で返す.差をとって「かかった時間」を測る
turtlefd・lt・goto …この教材でずっと使ってきた箱

箱の開け方は 3 通りあります.結果は似ていますが,意味が違います.

書き方呼び出し方性質と使いどころ
import randomrandom.randint(1, 6)箱ごと持ってくる.どの箱の道具かが一目でわかる.ふだんはこれ
from random import randintrandint(1, 6)使うものだけ名前を借りる.短く書けるが,出どころが見えなくなる
from random import *randint(1, 6)箱の中身を全部借りる.from turtle import * がこれ

import は,プログラムのいちばん上に書くのが決まりです. 先頭のコメントのすぐ下,ほかの処理より前に並べます.

import3.py
# 道具箱を 3 通りの書き方で開けてみる
import math
import random
from math import sqrt          # sqrt だけ名前を借りる

print(math.pi)
print(math.sqrt(2))
print(sqrt(2))                 # 借りたので math. が要らない

print(math.floor(3.7), math.ceil(3.2))    # 切り捨て・切り上げ
print(f"{math.sin(math.radians(30)):.3f}")

random.seed(1)                 # 毎回同じ結果にしたいときの「種」
print(random.randint(1, 6))
print(random.choice(["赤", "青", "黄"]))

a = [1, 2, 3, 4, 5]
random.shuffle(a)              # かきまぜる(a 自身が変わる)
print(a)
from ○○ import * は控えめに from ○○ import * は,箱の中の名前を全部そのまま持ってきます. 箱を 2 つ開けて同じ名前の道具があると, あとから開けたほうで上書きされてしまいます. 自分で作った変数や関数が消されることもあります. この教材で from turtle import * だけ特別に使っているのは, fd や lt をいちいち turtle.fd と書くのが 大変だからです.それ以外の箱は import random のほうを使ってください.
よくあるエラー NameError: name 'sqrt' is not defined と出たら, たいてい import の書き忘れです. math.sqrt と書くなら import math, sqrt と書くなら from math import sqrt が必要です.
虫食い虫食い 20-E さいころを振って記録する

さいころを 60 回振り,出た目を数えて表示します. この章で習った文字列の加工・None の調べ方・ f-string の書式指定を使う総合問題です. ____ を埋めてください.

fill20_dice.py
# さいころを 60 回振る

import random

random.seed(3)                 # 毎回同じ結果にする

kekka = []
for i in range(60):
    kekka.append(random.randint(1, 6))

# (1) 目ごとの回数を数える(辞書)
kazu = {}
for me in kekka:
    kazu[me] = kazu.get(me, 0) + 1

# (2) 最初の 10 回の目を「,」でつないで 1 行で表示する
print("最初の 10 回:", ",".____([str(me) for me in kekka[:10]]))

# (3) 1 回も出なかった目を調べる(get は無いキーで None を返す)
for me in range(1, 7):
    if kazu.get(me) ____ None:
        print(f"{me} の目は 1 回も出ませんでした")

# (4) けたをそろえて表示する(回数は 3 文字幅で右寄せ,割合は小数 1 けた)
for me in sorted(kazu):
    n = kazu[me]
    wariai = n / len(kekka) * 100
    bar = "■" * n
    print(f"{me} の目:{n:____} 回({wariai:____}%){bar}")


# (5) いちばん多かった目
def kaisu(kv):
    return kv[1]


narabi = sorted(kazu.items(), key=kaisu, reverse=True)
print(f"いちばん多かったのは {narabi[0][0]} の目で {narabi[0][1]} 回")

20.7 この先に学ぶこと

文法編はこの章で終わりです. 第 21〜25 章の設計編では,ここまでの文法を使って, データ設計・検証・クラス設計・JSON 保存へ進みます. 下の表のうち,クラス定義とファイル入出力は設計編で扱います. 外部ライブラリなどは,この教材の外で学ぶことになります. 「知らないことがある」と知っていることは,それ自体が力になります.

次に学ぶことどんなものかいつ必要になるか
クラス定義
class
データと処理をひとまとめにした新しい種類を,自分で作る書き方.この教材で使った Turtle() がまさにそれで,第23・24章で,作る側の設計を2回に分けて学びますプログラムが大きくなったとき.「オブジェクト指向」という言葉はここから始まります
ファイル入出力
open
データをファイルに保存し,読み戻す書き方.第25章でブラウザ内のファイルと,手元へのJSON保存・読み込みを扱います.プログラムを閉じてもデータを残したいとき.成績表,設定,ゲームのセーブデータ
外部ライブラリ
pip install
世界中の人が作って公開している道具箱を,あとから足して使う仕組み.表計算の pandas,グラフの matplotlib,数値計算の numpy,通信の requests など実務や研究で Python を使うとき.むしろここからが Python の本領です
その他正規表現,並行処理,型ヒント,while True: による本格的なループ(ブラウザでは固まるため)必要になったときに,1 つずつ

20.7.1 次に何を学べばよいか

道しるべを 4 つ置いておきます.順番に迷ったら,上から順でかまいません.

  1. 自分のパソコンで動かす.第 1 章でやったとおり,VS Code と Python を手元に用意してください.ブラウザの制限が無くなり,while True: もファイル操作も使えます.これがいちばん大きな一歩です.
  2. 公式チュートリアルを読む.docs.python.org/ja/3/tutorial/ に日本語版があります.この教材で習ったことがひととおり出てくるので,復習しながら,足りないところを埋められます.設計編で扱うクラス定義やファイル入出力の章もあるので,あわせて読むと理解が深まります.
  3. 作りたいものを 1 つ決める.文法を全部覚えてから作ろうとすると,たいてい始まりません.作りたいものを決めて,必要になった文法だけを調べる.これがいちばん早く上達するやり方です.
  4. 2 年次以降の科目につなげる.「データ構造とアルゴリズム」では,第 17 章・第 19 章で触れた話をきちんと学びます.ほかの言語を習うときは,「Python ではこう書いた」と対応づけながら読むと速いです.
ここまでで身につけてほしいこと 最後に 1 つだけ. プログラミングで本当に必要なのは,命令を暗記していることではありません. やりたいことを手順に分解できることと, 思いどおりに動かないときに原因を突きとめられることです. この 2 つは,第 2 章でかめに fd(100) と命令した日から, ずっと練習してきたことです. 使う言語が変わっても,この力はそのまま持っていけます.

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

書き方意味
break繰り返しをその場でやめる
continueその回の残りを飛ばして次の回へ
while 条件:条件が成り立つあいだ繰り返す.回数が決まっていないとき
abs(x)絶対値.符号を取り払った値
not A真偽をひっくり返す
A and B / A or B両方/どちらか一方でも
if a:a が空でなければ.空のリスト・空の文字列・0・None は偽
bool(x)x が真か偽かを確かめる
x in a / x not in a入っている/入っていない
0 <= x < 100連鎖比較.範囲の判定が数学と同じ見た目で書ける
len(s) / s[0] / s[0:3]文字列の長さ/1 文字/切り出し
s + t / s * 3つなぐ/くり返す
s.upper() / s.lower()大文字に/小文字に
s.strip()前後の空白・改行を取り除く
s.split(区切り)区切ってリストにする
区切り.join(リスト)リストをつなげて文字列にする
s.replace(前, 後)置きかえる
s.find(x)何番目にあるか.無ければ -1
f"{x}"f-string.文字列の中に値を埋め込む
f"{x:.2f}"小数点以下 2 けた
f"{x:>6}"6 文字ぶんの幅で右寄せ(< 左,^ 中央)
f"{n:03d}" / f"{n:,}"0 詰め/3 けた区切り
a, b = b, a2 つの値を入れ替える
return x, y2 つの値を返す(タプルになる)
None「値が無い」ことを表す特別な値
x is None / x is not NoneNone かどうかを調べる(== None とは書かない)
try: … except ValueError:失敗しても止まらないようにする
import random道具箱ごと開ける.random.randint(1, 6)
from math import sqrt道具を 1 つ借りる.sqrt(2)
from turtle import *箱の中身を全部借りる

演習

出発点のプログラムを「▶ この演習を開く」で右側に読み込み, それを発展させて作品にしてください. input() を使う演習には,右コンソールの入力行に あらかじめ値を入れてあります.書き換えて試してください. できあがったら「⤓ 保存」でファイルに保存して,手元に残しておきましょう.

演習演習 20-1 こわれない計算プログラム

何を入力されても止まらない計算プログラムを作ります. 出発点は,まったく備えのない状態です.実際に文字を入れて落としてみてください.

  1. try/except ValueError で,数でないものを入れられても止まらないようにする.
  2. 数でなかったら「「さん」は数ではありません.あと 2 回」のように表示して入力し直させる.聞き直しは 1 つの数につき3 回まで(for と break.while True: は使えません).
  3. 0 で割る失敗(ZeroDivisionError)にも備え,「0 では割れません」と表示して止まらないようにする.
  4. 3 回とも受け取れなかったときは値を None のままにしておき,is None で判定して「数が受け取れませんでした.終わります」と表示する.
  5. 受け取れたら,f"{a} + {b} = {a + b}" の形で和を,f"{a} ÷ {b} = {a / b:.3f}" の形で商(小数第 3 位まで)を表示する.
  6. これもやりましょう:範囲の判定も入れる.受け取る数は -1000 以上 1000 以下とし,連鎖比較 -1000 <= n <= 1000 が成り立たないときは「「5000」は範囲外です」と表示して入れ直させる(これも 3 回に数える).右コンソールの入力行には さん・3・5000・0 を1 行ずつ入れてあります.正しければ a = 3,b = 0 になり,「3 + 0 = 3」と「0 では割れません」が表示されます.
ヒント 入力し直させるときは,コンソールでもう一度打てば 何回ぶんでも試せます.わざと変な値を並べて,動きを確かめてください.
評価の目安(10 段階)

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

  1. 数でない入力をしても止まらず,try/except ValueError で受け止めて,決まった回数まで入力し直させる.
  2. 受け取れなかった値は None のままにし,is None で判定して,そのときの動きを決めている.
  3. 0 で割る失敗を except ZeroDivisionError で受け止め,止まらずにメッセージを出す.
  4. 連鎖比較 -1000 <= n <= 1000 で範囲を調べ,範囲外の数(例:5000)も入れ直させる.

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

  • 数を読む処理を関数にして,最小値・最大値を引数で変えられるようにする
  • 差・積も同じ形で表示する
  • f-string の書式で,割り算の結果のけた数をそろえる

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

演習演習 20-2 文字列であそぶ

入力された文を加工して,画面に描きます. 文字列のメソッドとスライスの練習です.

  1. 入力された文の文字数を表示する.
  2. 逆さまにしたものを表示する(s[::-1]).
  3. カンマ(,)で区切ってリストにし," / "(前後に空白のある /)でつなぎ直して表示する(split と join).
  4. 置きかえる前と後の言葉も input() で受け取り,別の言葉に置きかえて表示する(replace).
  5. 加工した結果(もとの文・逆さま・つなぎ直し・置きかえ)を,タートルの write で画面に縦に並べる.それぞれ小さな見出しを (-260, y) に,結果を (-260, y - 28) に書き,y を 150 から 80 ずつ下げる.4 組の(見出し, 結果)をタプルのリストにまとめ,1 つの for で y を下げながら書く(write を 4 組ぶん並べて書かない).
  6. これもやりましょう:回文かどうかを s == s[::-1] で判定し,いちばん下に「これは回文です」か「回文ではありません」を write する.入力の前後に空白が入っても正しく判定できるよう,先に s.strip() で空白を除いておく.

入力例:文 たーとる,ぐらふぃっくす,たのしい,置きかえる前 たーとる,後 かめ のとき, 文字数は 17,逆さまは いしのた,すくっぃふらぐ,るとーた, つなぎ直しは たーとる / ぐらふぃっくす / たのしい, 置きかえは かめ,ぐらふぃっくす,たのしい,判定は「回文ではありません」. 文を しんぶんし にすると「これは回文です」になります.

ヒント 文はカンマ(,)を含めて入力してください. 右コンソールの入力行には,文・置きかえる前の言葉・後の言葉を 1 行ずつ入れてあります.
評価の目安(10 段階)

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

  1. 入力された文を split(",") でリストにし,別の記号で join してつなぎ直している.
  2. 置きかえる前と後の言葉を input() で受け取り,replace で置きかえている.
  3. 加工した結果を(見出し, 結果)のタプルのリストにまとめ,1 つの for で y を 80 ずつ下げながら,見出しつきで write で画面に縦に並べている.
  4. strip で空白を除いてから s == s[::-1] で回文かどうかを判定し,結果を画面に書いている.

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

  • upper・find・count なども使って加工を増やす
  • カンマで区切った言葉ごとに,何文字あるかも表示する
  • 見出しと結果の位置を f-string の幅指定でそろえてコンソールにも表示する

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

演習演習 20-3 条件で仕分けるプログラム

and・or・not・連鎖比較・ in を使って,データを仕分けます.

  1. 点数のリストを,A(80 以上)・B(60 以上 80 未満)・C(60 未満)の 3 つに仕分ける.連鎖比較 60 <= t < 80 を使うこと.
  2. ありえない点数(0 未満や 100 より大きい)が混じっていたら,not (0 <= t <= 100) で見分けて continue で飛ばし,飛ばした個数を tobashita で数えて表示する.
  3. 正しければ A は [92, 100, 88, 91],B は [78, 61, 72, 66],C は [55, 45],飛ばしたのは 2 件(-3 と 120)になる.
  4. 仕分けた人数を,3 色の棒グラフか円の大きさで描き,人数を f"{len(a_group)} 人" の形で write する.棒グラフにするなら,棒の幅 80,高さは「人数 × 45」,下の辺を y = -120 にそろえ,x = -150 から 120 ずつ右へずらすと画面に収まる.
  5. これもやりましょう:ありえない点数を除いた点数のリストを内包表記で作り,any・all を使って「満点がいる? True」「全員合格? False」(合格は 60 点以上)の形で表示する.
評価の目安(10 段階)

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

  1. 連鎖比較(60 <= t < 80 など)で,点数を A・B・C に仕分けている.
  2. 0〜100 の範囲に入らない点数を,連鎖比較と not で見分けて飛ばし,飛ばした件数を表示している.
  3. 仕分けた人数を棒グラフか円の大きさで描き,人数を f-string で write している.
  4. ありえない点数を除いたリストを内包表記で作り,any で満点がいるか(True),all で全員合格か(False)を表示している.

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

  • 名前つきのデータ(タプルのリスト)にして,A 判定の人の名前を内包表記で取り出す
  • 平均点を :.1f で画面に書き入れる

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

演習演習 20-4 書式をそろえた一覧表

f-string の書式を使って,けたのそろった表をコンソールに作ります.

  1. 商品名・個数・単価のデータから,小計(個数 × 単価)を計算する.
  2. f"{x:>8}" などを使って,数の右はしがそろった表をコンソールに表示する.列は「商品 :<10」「個数 :>6」「単価 :>8」「小計 :>10」の幅にする.見出しの行と区切り線("-" * 40)も入れること.
  3. 金額は f"{x:,}" で3 けた区切りにする.
  4. 小計の合計と,1 品あたりの小計の平均も出す.平均は小数点以下 1 けた(:.1f).正しければ合計は 2,520,平均は 630.0 になる.
  5. 表の最後に区切り線をもう 1 本引き,その下に合計の行を表と同じ列幅で表示する.「合計」は商品の列(:<10)に書き,個数・単価の列は空の文字列 '' で幅だけ埋め,合計 2,520 の右はしが小計の列の右はしとそろうようにする(幅と 3 けた区切りは :>10, のように 1 つの書式にまとめて書ける).
  6. これもやりましょう:小計の安い順に並べ替えてから,コンソールの表と画面の表の両方を表示する.小計を返す関数を def で作り,sorted(shina, key=その関数) に渡す(第 19 章).正しければ 定規(350),消しゴム(550),ノート(660),えんぴつ(960)の順になる.
ヒント 幅をそろえるには,見出しの行・データの行・合計の行で同じ幅の指定を使います. 1 行ずつ数え直さなくて済むよう,幅は列ごとに決めておきましょう. 日本語の文字は 1 文字が英数字 2 文字ぶんの幅で表示されることがあり,商品名の列は少しずれて見えることがあります.
評価の目安(10 段階)

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

  1. 見出しの行と区切り線のある表を,f-string の幅指定(:>8 など)で数の右はしがそろうようにコンソールに表示している.
  2. 金額を :, で 3 けた区切りにしている.
  3. 小計の合計と,1 品あたりの小計の平均(:.1f)を表示している.
  4. 合計の行を表と同じ列幅で表示し,合計 2,520 の右はしを小計の列にそろえている.
  5. 小計を返す関数を key= に渡し,小計の安い順(定規・消しゴム・ノート・えんぴつ)に並べて表示している.

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

  • 高い順・安い順を input() で選べるようにする
  • 同じ表をタートルの write で画面にも描く(等幅でないので,列ごとに x 座標を変えて書く)
  • 商品を input() で追加できるようにし,数でない個数には try で備える

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

自由演習 20-5 自由制作:総まとめ

文法編の最後の課題です.ここまでに習ったことを使って,好きなものを作ってください. テーマは自由です.絵でも,ゲームでも,計算でも,データの集計でもかまいません.

  • 関数(def)を 2 つ以上作ること(第 13 章・第 14 章)
  • リスト・辞書・タプル・集合のうち 2 つ以上を使うこと(第 16 章・第 18 章・第 19 章)
  • 繰り返しと条件分岐を使うこと(第 5 章・第 6 章)
  • この章で新しく習ったもの(①f-string の書式指定,②文字列のメソッド,③try/except 例外名,④is None,⑤真偽値の省略・連鎖比較)から2 つ以上使い,使った場所にコメントで番号を書くこと
  • 先頭にコメントで,題名・氏名・日付・何をするプログラムかを書くこと
  • 読む人のためのコメントを要所に入れること.「何をしているか」ではなく「なぜそうしているか」を書く
ヒント アイデアが浮かばないときは,これまでの回の演習を 1 つ選んで 作り直すのがおすすめです. 当時より道具が増えているので,ずっと短く,きれいに書けるはずです. 「あのときはこう書いたが,いまならこう書く」という比較そのものが, ここまでの成果です.
評価の目安(10 段階)

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

  1. 関数(def)を 2 つ以上作り,リスト・辞書・タプル・集合のうち 2 つ以上を使い,繰り返しと条件分岐を使っている.
  2. この章で新しく習ったもの(①f-string の書式指定 ②文字列のメソッド ③try/except 例外名 ④is None ⑤真偽値の省略・連鎖比較)を2 つ以上使い,使った場所にコメントで番号を書いている.
  3. 先頭に題名・氏名・日付・何をするプログラムかを書き,要所に「なぜそうしているか」のコメントがある.

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

  • 前に作った演習を作り直し,前と後の両方を残して比べる
  • どんな入力をされても止まらないように備える
  • よく使う値(回数・範囲・位置など)を変数や関数の引数にまとめ,1 か所変えるだけで全体の動きが変わるようにする

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

まとめ

  • break は繰り返しを終わらせ,continue は次の回へ進む.効くのはいちばん内側の繰り返し 1 つだけ.
  • 何回で終わるか分からない繰り返しは,while か上限つきの for と break で書く.while True: は使わない.
  • not・and・or で条件を組み立てる.混ざるときはかっこを惜しまない.
  • 空のリスト・空の文字列・0・None は偽.だから if a: で「中身があるか」を書ける.
  • 0 <= x < 100 という連鎖比較が書ける.範囲の判定が数学と同じ見た目になる.
  • 文字列はリストに似ている.split で区切り,join でつなぎ,replace で置きかえる.
  • f-string f"{x:.2f}" でけた数や幅をそろえられる.表がきれいになる.
  • a, b = b, a,return x, y.Python は複数の値をまとめてあつかえる.
  • None は「値が無い」印.調べるときは is None.
  • try/except ValueError で,入力の失敗に備える.受け止める例外の種類は必ず書く.
  • import はふだん import random の形で.from ○○ import * は名前がぶつかるので控えめに.

ここまでが文法の基礎です.次の第 21 章からは,データと処理を整理する設計へ進みます. 第 2 章で fd(100) と 1 行書いたところから, データを集計して絵にするところまで来ました. 行きづまったら,速度を落として,少しずつ書いて, print で覗いてみる.やり方は第 2 章から何も変わりません.

復習:虫食いで確かめる

コードの ____ を埋めてください.実行前に結果を予測し,実行後に問題文の条件と照合しましょう.assert は条件が成り立つかを調べ,成り立たないとエラーになります.

虫食い虫食い・復習 1 不正な整数を扱う

abc を整数に変換したときの例外を受け止めます.エラーで止まらず「整数を入力してください」と表示するようにしてください.

fill_review_lec14_1.py
try:
    number = int("abc")
____ ____:
    print("整数を入力してください")