辞書
名前で引ける入れ物.データに意味を持たせる.
リストは便利な入れ物でした.
しかし,リストからデータを取り出すには番号が要ります.
a[0],a[3].
「0 番目には誰の点数が入っているんだっけ」と,
いちいち思い出さなければなりません.
今回習う辞書(dictionary)は,
番号ではなく名前で引ける入れ物です.
ten["さくら"] と書けば,さくらさんの点数が出てきます.
紙の辞書で「りんご」を引くと意味が書いてあるのと同じ仕組みです.
番号が名前に変わるだけ,と思うかもしれません. しかしこの変化は大きいのです. データに意味が付くからです. 今回の最後には,入力された言葉に応じて絵を描き分けるプログラムを作ります.
- リストでは足りない場面を説明できる
{ }で辞書を作り,キーと値の関係を説明できるd["key"]で取り出す・書き換える・付け加えることができるinとget()で,安全にキーを引けるforとitems()で辞書の中身を全部たどれる- 辞書とリストを組み合わせて,少し複雑なデータを表せる
- 辞書を使って,入力された言葉に応じた絵を描くプログラムが書ける
list・dict・set・tupleの使い分けがわかり,公式ドキュメントを引ける
18.1 リストでは足りない場面
5 人の点数を持っておきたいとします.リストならこう書けます.
ten = [78, 92, 65, 88, 71] print(ten[2]) # → 65
65 は誰の点数でしょうか.分かりません.
「2 番目はさくらさん」という約束を,プログラムの外側で
覚えておかなければならないのです.これは危険です.
1 人減らしただけで,全部の番号がずれてしまいます.
18.1.1 2 本のリストで代用してみる
よくある工夫が,名前のリストと点数のリストを 2 本並べるやり方です. 同じ番号どうしが対応している,という約束にします.
# 名前のリストと点数のリストを並べて使う
namae = ["あかり", "けんた", "さくら", "たろう", "なな"]
ten = [78, 92, 65, 88, 71]
shirabetai = "さくら"
# 名前のリストから場所を探して(=第 17 章の線形探索)
k = -1
for i in range(len(namae)):
if namae[i] == shirabetai:
k = i
break
# その場所の点数を取り出す
if k >= 0:
print(shirabetai, "さんの点数は", ten[k], "点です")
else:
print(shirabetai, "さんは名簿にいません")
動きます.しかし,うれしくありません.
- 点数を 1 つ知るだけで,毎回リストを端から探すことになる.人数が増えるほど遅くなる.
- 2 本のリストの長さと順番がずれたら終わり.1 人だけ消したりすると,静かに壊れる.
- そもそも,書くのが面倒.毎回 8 行も書きたくない.
「名前から値を引く」というのは, プログラムを書いているとあまりにもよく出てくる要求です. だから,はじめから道具が用意されています.それが辞書です.
18.2 辞書を作る
辞書は波かっこ { } で作ります.
キーと値を : でつなぎ,
組を , で区切って並べます.
ten = {"あかり": 78, "けんた": 92, "さくら": 65, "たろう": 88, "なな": 71}
# ↑キー ↑値
| 言葉 | 意味 | 例 |
|---|---|---|
| キー(key) | 引くときの手がかり.紙の辞書の「見出し語」 | "さくら" |
| 値(value) | 引いて出てくる中身.紙の辞書の「意味」 | 65 |
| 組 | キーと値のひとそろい.辞書は組の集まり | "さくら": 65 |
長い辞書は,行を分けて書くと読みやすくなります.
最後の組のうしろにも , を付けてよいのが便利なところです.
ten = {
"あかり": 78,
"けんた": 92,
"さくら": 65,
"たろう": 88,
"なな": 71,
}
18.2.1 取り出す・書き換える・付け加える
取り出すときは,リストと同じ角かっこを使います. 中に書くのが番号ではなくキーになるだけです.
ten = {"あかり": 78, "けんた": 92, "さくら": 65}
# 取り出す
print(ten["さくら"]) # → 65
# 書き換える(すでにあるキー)
ten["さくら"] = 70
print(ten["さくら"]) # → 70
# 付け加える(まだ無いキー)
ten["たろう"] = 88
print(ten)
# 何組あるか
print("人数は", len(ten), "人")
ten["さくら"] = 70 は,
「さくら」がすでにあれば書き換え,無ければ新規追加です.
リストの a[5] = 3 が「5 番目が無ければエラー」だったのと,ここが違います.
便利な反面,キーを打ち間違えると,静かに別の組が増えます.
「さくら」と「さくら 」(末尾に空白)は別のキーです.
空の辞書は {} で作れます.
そこへ 1 組ずつ入れていくのが,よく使う書き方です.
d = {} # 空の辞書
d["りんご"] = "red"
d["みかん"] = "orange"
print(d) # → {'りんご': 'red', 'みかん': 'orange'}
18.2.2 無いキーを引くとエラー
辞書に入っていないキーを引くと,プログラムはその場で止まります.
ten = {"あかり": 78, "けんた": 92}
print(ten["ゆうき"])
# → KeyError: 'ゆうき'
KeyError は「そんなキーはありません」という意味です.
入力された言葉を辞書で引くようなプログラムでは,
ユーザが何を入力するか分からないので,必ず起きます.
次の節で,その備え方を習います.
色の日本語名から,タートルで使える色の名前を引く辞書を作り, その色で点を打つプログラムです. ____ を埋めてください.
from turtle import *
ht()
iro = {"あか": "red", "あお": ____, "きいろ": "gold", "みどり": "seagreen"}
namae = ["あか", "きいろ", "みどり", "あお"]
x = -150
for n in namae:
pu()
goto(x, 0)
pencolor(iro[____]) # 日本語名から色の名前を引く
dot(70)
pu()
goto(x - 22, -70)
pencolor("black")
write(____, font=("Arial", 14, "normal"))
x = x + 100
print("辞書には", ____(iro), "色入っています")
done()
18.3 キーがあるか調べる
18.3.1 in で確かめる
リストのときと同じ in が使えます.
ただし辞書の in が調べるのは,キーのほうです.
ten = {"あかり": 78, "けんた": 92, "さくら": 65}
print("さくら" in ten) # → True(キーにある)
print("ゆうき" in ten) # → False
print(65 in ten) # → False(値は調べない!)
# 値のほうを調べたいときは values() を付ける
print(65 in ten.values()) # → True
# 安全に引く定石
namae = "ゆうき"
if namae in ten:
print(namae, "さんは", ten[namae], "点")
else:
print(namae, "さんは名簿にいません")
in は中で線形探索をしている,と話しました.
辞書の in は違います.
辞書は,中身がどれだけ増えても,ほぼ一瞬でキーを見つけられる
仕掛け(ハッシュ表といいます)で作られています.
1000 人分でも 100 万人分でも,引く速さはほとんど変わりません.
18.1.1 節の「2 本のリスト」方式との,いちばん大きな違いがこれです.
18.3.2 get() — 無くてもエラーにしない
「無ければこの値ということにしてほしい」という場面はよくあります.
get() を使うと 1 行で書けます.
ten = {"あかり": 78, "けんた": 92, "さくら": 65}
print(ten.get("さくら")) # → 65(ふつうに取り出せる)
print(ten.get("ゆうき")) # → None(エラーにならない)
print(ten.get("ゆうき", 0)) # → 0(無いときの値を指定できる)
# 出席回数を数える,というよくある使い方
kiroku = ["あかり", "けんた", "あかり", "さくら", "あかり", "けんた"]
kaisu = {}
for n in kiroku:
kaisu[n] = kaisu.get(n, 0) + 1 # 無ければ 0 から数え始める
print(kaisu)
| 書き方 | キーがあるとき | キーが無いとき |
|---|---|---|
d[k] | 値を返す | エラー(KeyError) |
d.get(k) | 値を返す | None を返す |
d.get(k, x) | 値を返す | x を返す |
k in d | True | False |
kaisu[n] = kaisu.get(n, 0) + 1 は,ぜひ覚えてほしい 1 行です.
「数える」「集計する」という処理は,ほとんどこの形で書けます.
文字列の中に,どの文字が何回出てくるかを数えて, 多い順に棒グラフで描くプログラムです. ____ を埋めてください.
for c in s: と書くと,文字列 s の文字を
1 つずつ取り出せます.文字列も「並んだもの」なので,
リストと同じように for で回せるのです.
from turtle import *
ht()
speed(0)
s = "abracadabra"
# 数える
kaisu = {}
for c in s:
kaisu[c] = kaisu.____(c, 0) + 1
print(kaisu)
# 多い順に並べ替える(キーのリストを作って並べ替える)
moji = list(kaisu.keys())
moji.sort(key=lambda c: -kaisu[c])
# 棒グラフにする
x = -120
for c in moji:
fillcolor("mediumpurple")
pu()
goto(x, -80)
seth(0)
pd()
begin_fill()
fd(40)
lt(90)
fd(kaisu[____] * 30)
lt(90)
fd(40)
lt(90)
fd(kaisu[c] * 30)
lt(90)
end_fill()
pu()
goto(x + 12, -104)
write(____, font=("Arial", 16, "normal"))
x = x + 55
done()
18.4 中身を全部たどる
18.4.1 for で回す
for k in d: と書くと,キーが 1 つずつ取り出されます.
値ではありません.ここは最初にとまどうところです.
ten = {"あかり": 78, "けんた": 92, "さくら": 65}
print("--- キーだけ ---")
for k in ten:
print(k)
print("--- キーと値(キーで引く) ---")
for k in ten:
print(k, "さんは", ten[k], "点")
print("--- キーと値(items) ---")
for k, v in ten.items():
print(k, "さんは", v, "点")
print("--- 値だけ ---")
for v in ten.values():
print(v)
print("合計", sum(ten.values()), "点/平均", sum(ten.values()) / len(ten), "点")
| 書き方 | 取り出されるもの |
|---|---|
for k in d: | キー(d.keys() と同じ) |
for v in d.values(): | 値 |
for k, v in d.items(): | キーと値の両方 |
len(d) | 組の数(要素数) |
for k, v in d.items(): の k, v は,
第 17 章に出てきた a, b = b, a と同じ仕掛けです.
items() は「キーと値がひと組になったもの」を返すので,
それを 2 つの変数に配っているのです.
辞書の中身は,書いた順(入れた順)に取り出されます. 昔の Python では順番がばらばらでしたが,いまは入れた順と決まっています.
18.4.2 辞書からグラフを描く
キーを名前に,値を棒の高さにすれば,そのままグラフになります. 辞書はグラフと相性がよいのです.
# 辞書から棒グラフを描く
from turtle import *
ten = {"あかり": 78, "けんた": 92, "さくら": 65, "たろう": 88, "なな": 71}
ht()
speed(0)
pensize(1)
pencolor("dimgray")
x = -175
for namae, ten_su in ten.items():
fillcolor("steelblue")
pu()
goto(x, -120)
seth(0)
pd()
begin_fill()
fd(48)
lt(90)
fd(ten_su * 2)
lt(90)
fd(48)
lt(90)
fd(ten_su * 2)
lt(90)
end_fill()
pu()
goto(x + 4, -145)
pencolor("black")
write(namae, font=("Arial", 14, "normal"))
goto(x + 10, -112 + ten_su * 2)
write(ten_su, font=("Arial", 13, "normal"))
pencolor("dimgray")
x = x + 72
print("平均", sum(ten.values()) / len(ten), "点")
done()
ten をそのまま棒グラフにしたもの.18.4.3 組を消す — del
要らなくなった組は del で消せます.
ten = {"あかり": 78, "けんた": 92, "さくら": 65}
print(ten, len(ten))
del ten["けんた"]
print(ten, len(ten))
# 無いキーを del するとエラーになるので,先に確かめる
if "ゆうき" in ten:
del ten["ゆうき"]
else:
print("ゆうき は元からいません")
# pop なら,無いときの値を決めておける
x = ten.pop("ゆうき", -1)
print("消した値:", x)
ten.clear() # 全部消す
print(ten, len(ten))
for で辞書を回している最中に
del で組を消してはいけません.
RuntimeError: dictionary changed size during iteration というエラーになります.
どうしても消したいときは,消すキーを先にリストに集めておき,
for を抜けてから消します.
18.5 キーに使えるもの
キーには,文字列のほかに数も使えます. 「学生番号 → 点数」「年 → 人口」のように.
# 学生番号(数)をキーにする
ten = {2301: 78, 2302: 92, 2315: 65}
print(ten[2302])
# 数のキーは「番号」ではないので,とびとびでもよい
print(2315 in ten) # → True
print(0 in ten) # → False(リストなら 0 番目は必ずある)
# 位置(x, y)をキーにすることもできる(タプルを使う)
masu = {(0, 0): "白", (1, 0): "黒", (2, 3): "白"}
print(masu[(1, 0)])
# リストはキーにできない
# d = {[1, 2]: "だめ"} # → TypeError: unhashable type: 'list'
| キーに使えるか | 例 | 理由 |
|---|---|---|
| ○ 文字列 | "さくら" | 作ったあとで中身が変わらない |
| ○ 数 | 2302, 3.14 | 同上 |
| ○ タプル | (1, 0) | 同上(18.9 節) |
| × リスト | [1, 2] | あとから中身を変えられてしまうため |
| × 辞書 | {"a": 1} | 同上 |
なお,値のほうには何でも入れられます. 数,文字列,リスト,辞書,そして関数まで.次の節で見ていきます.
18.6 辞書とリストを組み合わせる
18.6.1 値がリストの辞書
「1 人につき複数の値」を持ちたいときは,値をリストにします.
# 1 人につき 3 回分のテストの点
ten = {
"あかり": [78, 82, 91],
"けんた": [92, 88, 85],
"さくら": [65, 70, 74],
}
print(ten["あかり"]) # → [78, 82, 91]
print(ten["あかり"][2]) # → 91(3 回目の点)
for namae, ten_list in ten.items():
heikin = sum(ten_list) / len(ten_list)
print(namae, "さん:", ten_list, "平均", heikin, "点")
# 1 回分を付け足す
ten["さくら"].append(80)
print(ten["さくら"])
ten["あかり"][2] は「辞書を引いて,出てきたリストの 2 番目」という意味です.
左から順に読むと分かりやすくなります.
18.6.2 辞書が並んだリスト
逆に,リストの中に辞書を並べることもあります. 「1 件=1 つの辞書」と考えると,表(エクセルの 1 行)をそのまま表せます.
# 1 件が 1 つの辞書.よく使う形
hoshi = [
{"namae": "シリウス", "akarusa": 25, "iro": "white"},
{"namae": "ベテルギウス", "akarusa": 18, "iro": "orangered"},
{"namae": "リゲル", "akarusa": 20, "iro": "lightskyblue"},
]
for h in hoshi:
print(h["namae"], "/明るさ", h["akarusa"], "/色", h["iro"])
# 明るい順に並べ替える(第 17 章の sort と組み合わせる)
hoshi.sort(key=lambda h: -h["akarusa"])
print("いちばん明るいのは", hoshi[0]["namae"])
key=lambda h: -h["akarusa"] は
「明るさにマイナスを付けた値の小さい順に並べる」,
つまり明るい順という意味です.
lambda は「名前のない小さな関数」を作る書き方で,
sort に「何を基準に比べるか」を教えるときによく使います.
いまは形として覚えておけば十分です.
上の hoshi を使って,星空を描きます.
辞書から位置・大きさ・色を取り出して点を打ってください.
____ を埋めてください.
from turtle import *
ht()
bgcolor("midnightblue")
hoshi = [
{"namae": "シリウス", "x": -150, "y": 60, "size": 26, "iro": "white"},
{"namae": "ベテルギウス", "x": 40, "y": 110, "size": 20, "iro": "orangered"},
{"namae": "リゲル", "x": 120, "y": -40, "size": 22, "iro": "lightskyblue"},
{"namae": "プロキオン", "x": -60, "y": -90, "size": 16, "iro": "lightyellow"},
]
for h in ____:
pu()
goto(h["x"], h[____])
pencolor(h["iro"])
dot(h[____])
pu()
goto(h["x"] - 30, h["y"] - 38)
pencolor("lightgray")
write(h["namae"], font=("Arial", 12, "normal"))
done()
18.7 辞書で図形を選ぶ
辞書の値には数や文字列だけでなく,描き方を決める情報も入れられます. 「言葉 → 図形」の対応表を作ってみましょう.
# 言葉 → 角の数 の辞書で,図形を描き分ける
from turtle import *
kado = {"さんかく": 3, "しかく": 4, "ごかく": 5, "ろっかく": 6, "はちかく": 8}
iro = {"さんかく": "tomato", "しかく": "royalblue", "ごかく": "seagreen",
"ろっかく": "goldenrod", "はちかく": "mediumpurple"}
ht()
speed(0)
pensize(3)
kotoba = "ごかく"
n = kado[kotoba] # 角の数を引く
pencolor(iro[kotoba]) # 色を引く
pu()
goto(-60, -70)
seth(0)
pd()
for i in range(n):
fd(120)
lt(360 / n) # 第 2 章でやった 360 ÷ n
print(kotoba, "は", n, "角形です")
done()
kotoba = "ごかく" のときの結果.言葉を変えれば図形が変わる.if を 1 つも書いていないのがポイントです.
もし辞書を使わなければ,こう書くことになります.
if kotoba == "さんかく":
n = 3
pencolor("tomato")
elif kotoba == "しかく":
n = 4
pencolor("royalblue")
elif kotoba == "ごかく":
n = 5
pencolor("seagreen")
elif ...
図形を 1 つ増やすたびに elif が 3 行ずつ伸びていきます.
辞書なら,表に 1 行足すだけです.
長い elif の列を見たら,辞書にできないか考える.
これはプログラミングの定石の 1 つです.
曜日から色を引く辞書と,曜日から半径を引く辞書を使って, 円を 7 つ並べて描きます.____ を埋めてください.
for k, v in d.items(): を使うと,
キーと値を同時に取り出せます(18.4.1 節).
from turtle import *
ht()
speed(0)
pensize(3)
iro = {
"月": "silver", "火": "tomato", "水": "royalblue",
"木": "seagreen", "金": "gold", "土": "steelblue", "日": "crimson",
}
ookisa = {
"月": 20, "火": 24, "水": 22, "木": 26, "金": 30, "土": 34, "日": 34,
}
x = -180
for youbi, col in iro.____():
pu()
goto(x, 0)
seth(0)
pd()
pencolor(____)
circle(ookisa[____])
pu()
goto(x - 6, -50)
pencolor("black")
write(youbi, font=("Arial", 15, "normal"))
x = x + 60
done()
18.8 絵辞書をつくる
いよいよ今回の目玉です. 入力された言葉に応じた絵を描くプログラムを作ります.
18.8.1 絵を描く関数を用意する
まず,果物を描く関数を 4 つと,「見つかりません」の絵を 1 つ用意します. どれも引数なし・画面の中央に描くという約束にそろえておきます. この「そろえておく」ことが,あとで効いてきます.
ringo()ichigo()suika()mikan()notfound()18.8.2 辞書に関数そのものを入れる
ここで,少し驚くことをします. 辞書の値に,関数そのものを入れます.
e = {"りんご": ringo, "いちご": ichigo, "すいか": suika, "みかん": mikan}
# ↑かっこを付けない
ringo() と書くと「関数を呼ぶ」ですが,
ringo とかっこを付けずに書くと,
「関数そのもの」という値になります.
辞書から取り出したあとでかっこを付ければ,そのとき呼ばれます.
f = e["りんご"] # 関数そのものを取り出す(まだ描かれない) f() # ここで呼ばれる → りんごが描かれる e["りんご"]() # 1 行にまとめてもよい
# 絵辞書:言葉を入れると,その絵が出てくる
from turtle import *
def ringo():
color("saddlebrown")
pensize(8)
pu()
goto(0, 40)
seth(90)
pd()
fd(35)
pensize(2)
color("crimson")
pu()
goto(0, -60)
seth(0)
pd()
begin_fill()
circle(55)
end_fill()
def ichigo():
color("crimson")
pu()
goto(-45, 40)
pd()
begin_fill()
goto(45, 40)
goto(0, -65)
goto(-45, 40)
end_fill()
color("seagreen")
pu()
goto(-52, 42)
pd()
begin_fill()
goto(52, 42)
goto(0, 72)
goto(-52, 42)
end_fill()
def mikan():
color("orange")
pu()
goto(0, -60)
seth(0)
pd()
begin_fill()
circle(58)
end_fill()
color("seagreen")
pu()
goto(0, 50)
pd()
begin_fill()
goto(42, 76)
goto(4, 66)
goto(0, 50)
end_fill()
def notfound():
color("gray")
pu()
goto(-22, -45)
pd()
write("?", font=("Arial", 110, "bold"))
ht()
speed(0)
pensize(2)
# 言葉 → 絵を描く関数 の辞書
e = {"りんご": ringo, "いちご": ichigo, "みかん": mikan}
kotoba = input("調べたい言葉:")
if kotoba in e:
e[kotoba]() # 辞書から関数を取り出して,呼ぶ
print(kotoba, "の絵を描きました")
else:
notfound()
print(kotoba, "は辞書にありません")
done()
右コンソールの入力行に いちご と入れてあります.
りんご や みかん,
辞書に無い言葉(ばなな など)に書き換えて,実行してみてください.
いちご と入力したときの結果.in と
e[kotoba] の 2 つに置き換わります.
道具が変わると,プログラムの形そのものが変わるという良い例です.
== で中身を比べられます.
"りんご" == "りんご" は True です.安心して使ってください.
(なお,Python には「同じ物体か」を調べる is もありますが,
文字列や数を比べるのに使ってはいけません.)
18.9 自分で調べる
ここまでで,データをまとめて扱う道具が 2 つになりました. Python には,あと 2 つよく使うものがあります. 集合(set)とタプル(tuple)です. 4 つまとめて整理しておきましょう.
| 名前 | 書き方 | 引き方 | 得意なこと |
|---|---|---|---|
リスト list | [1, 2, 3] | 番号 a[0] | 順番が大事なもの.同じ値が何度あってもよい |
辞書 dict | {"a": 1} | キー d["a"] | 名前から値を引くこと.速い |
集合 set | {1, 2, 3} | 引けない(有無だけ) | 重複を消す・入っているか調べる・共通部分を求める |
タプル tuple | (1, 2) | 番号 t[0] | あとから変えない組.辞書のキーにできる |
# リスト:順番がある.重複してよい
a = [3, 1, 4, 1, 5, 9, 2, 6]
print(a[0], len(a))
# 集合:重複が消える.順番は無い
s = set(a)
print(s, len(s))
print(3 in s)
kudamono1 = {"りんご", "みかん", "すいか"}
kudamono2 = {"みかん", "いちご"}
print(kudamono1 & kudamono2) # 両方にあるもの
print(kudamono1 | kudamono2) # どちらかにあるもの
print(kudamono1 - kudamono2) # 1 にだけあるもの
# タプル:あとから変えられない組
t = (100, 200)
x, y = t # 一度に 2 つの変数へ
print(x, y)
# t[0] = 5 # → TypeError(変えられない)
# 辞書:名前で引く
d = {"あかり": 78, "けんた": 92}
print(d["けんた"])
{} は空の辞書であって,空の集合ではありません.
空の集合が欲しいときは set() と書きます.
Python の文法の中で,ちょっと意地悪なところです.
どれを使うか迷ったら,やりたいことを日本語で言ってみると決まります.
- 「1 番目,2 番目…と順に並べたい」 → リスト
- 「名前で引きたい」 → 辞書
- 「ダブっているものを消したい」「入っているかだけ知りたい」 → 集合
- 「2 つ(3 つ)をひとまとめにして渡したい」 → タプル
append すればいくらでも伸びます.
「配列」という言葉を見かけたときは,
「大きさが決まっているリスト」だと思ってください.
18.9.1 公式ドキュメントの読み方
ここまで習ってきた命令は,Python が用意してくれた道具のごく一部です. 「こんなことができる命令はないかな」と思ったら, 公式ドキュメントを見ます.日本語版があります.
| 場所 | 何が書いてあるか |
|---|---|
| Python チュートリアル docs.python.org/ja/3/tutorial/ | 読み物として最初から読めるもの.リスト・辞書の章がおすすめ |
| 組み込み型 docs.python.org/ja/3/library/stdtypes.html | list・dict・set・str に何ができるかの一覧 |
| 標準ライブラリ docs.python.org/ja/3/library/ | random・math・time などの道具箱の説明 |
| turtle docs.python.org/ja/3/library/turtle.html | タートルの命令の一覧(この教材で使えるのはその一部です) |
ドキュメントには,独特の書き方の約束があります.
たとえば get() の説明はこう書かれています.
get(key, default=None)
key が辞書にあれば key に対する値を,なければ default を返します.
key… 必ず書く引数default=None… 省略できる引数.省略するとNoneになる,という意味- だから
d.get(k)ともd.get(k, 0)とも書ける
この読み方が分かると,sorted(a, reverse=True) や
write(arg, align="center") のような書き方も,
自分でドキュメントから見つけられるようになります.
print(dir({})) と書けば辞書にできることの一覧が出ますし,
help(dict.get) と書けば説明が読めます
(この教材の画面でも動きます.試してみてください).
アンケートの回答から,何種類の答えがあったかと それぞれ何人かを求め,円の大きさで描きます. ____ を埋めてください. 種類を数えるのは集合,人数を数えるのは辞書の仕事です.
from turtle import *
ht()
speed(0)
pensize(2)
kotae = ["いぬ", "ねこ", "いぬ", "うさぎ", "ねこ", "いぬ", "ねこ", "いぬ"]
# 何種類あったか(集合を使う)
shurui = ____(kotae)
print("答えは", len(shurui), "種類ありました")
# それぞれ何人か(辞書を使う)
ninzu = {}
for k in kotae:
ninzu[k] = ninzu.get(k, ____) + 1
print(ninzu)
# 円の大きさで描く
iro = {"いぬ": "sienna", "ねこ": "dimgray", "うさぎ": "hotpink"}
x = -140
for k, n in ninzu.____():
pu()
goto(x, 0)
pencolor(iro[k])
dot(n * 28)
pu()
goto(x - 20, -70)
pencolor("black")
write(k, font=("Arial", 14, "normal"))
goto(x - 12, -95)
write(str(____) + " 人", font=("Arial", 13, "normal"))
x = x + 140
done()
18.10 この章で出てきた命令
| 書き方 | 意味 |
|---|---|
d = {} | 空の辞書を作る |
d = {"a": 1, "b": 2} | キーと値の組を書いて辞書を作る |
d[k] | キー k の値を取り出す.無ければ KeyError |
d[k] = v | キー k の値を v にする.無ければ新しく作る |
k in d | キー k があれば True |
d.get(k) | 値.無ければ None |
d.get(k, x) | 値.無ければ x |
len(d) | 組の数 |
for k in d: | キーを 1 つずつ取り出す |
d.keys() | キーの一覧 |
d.values() | 値の一覧 |
d.items() | キーと値の組の一覧.for k, v in … で使う |
del d[k] | キー k の組を消す |
d.pop(k, x) | 消しながら値を取り出す.無ければ x |
d.clear() | 全部消す |
set(a) | リスト a から重複を消した集合を作る |
(x, y) | タプル.あとから変えられない組 |
help(dict.get) | その命令の説明を表示する |
演習
出発点のプログラムを「▶ この演習を開く」で右側に読み込み,
それを発展させて作品にしてください.
input() を使う演習には,右コンソールの入力行に
あらかじめ値を入れてあります.書き換えて試してください.
入力に慣れるための演習です.次の順に作ってください.
- 入力された言葉を,そのまま画面の中央に
writeで表示する(おうむ返し). - ことばの辞典を辞書で作り,入力された言葉の意味を表示する.5 語以上入れること.
- 辞書に無い言葉が入力されたら,「その言葉は知りません」と表示する(
inかget()). - 余裕があれば,知らない言葉が来たときにその場で意味を入力させて辞書に登録し,登録後の辞書の中身を全部表示する.
input() を 2 回書けば,
input() が上から順に 1 行ずつ読み取ります.
名詞と動詞を集めておいて, でたらめな文を作るプログラムです.
- 辞書
tangoを作り,"めいし"と"どうし"をキーに,言葉のリストを値として入れる(18.6.1 節). random.choice(リスト)で 1 つ選び,「○○が△△」という文を作って画面にwriteする.- 文を 5 つ作り,縦に並べて表示する.
- 余裕があれば,
"けいようし"を足して「○○な○○が△△」にする.入力された言葉を辞書に登録できるようにする.
random.choice を使うには,先頭に import random が要ります.
リストに言葉を足すのは tango["めいし"].append("ねこ") です.
絵と単語の辞書を使ったタイピングゲームを作ってください.
- 「単語 → その絵を描く関数」の辞書を作る(18.8 節).3 語以上.
- 問題の絵を 1 つ描き,その名前を入力させる.
- 合っていれば「せいかい」,違えば「ざんねん」と表示する.
time.time()で入力にかかった秒数を測り,表示する.- 余裕があれば,3 問続けて出し,正解数と合計時間,1 問あたりの平均時間を表示する.
time.time() は「いまの時刻(秒)」を返します.
入力の前後で 2 回呼び,引き算すればかかった時間が分かります.
round(x, 2) と書くと,小数第 2 位までに丸められます.
「学生番号 → 点数のリスト」という辞書から,成績表を作ってください.
- 1 人ずつ,3 回のテストの平均点を計算する.
- 平均点で評価(80 以上は A,70 以上は B,60 以上は C,それ未満は D)を付ける.評価は辞書ではなく
ifで決める. - 平均点を棒グラフで描き,棒の上に評価を
writeする. - 評価ごとの人数を数えて表示する(
get()を使った数え方). - 余裕があれば,平均点の高い順に並べ替えてから描く(第 17 章の復習).
同じ目的でも,使う道具を変えるとプログラムの形が変わります(18.9 節). 次の「2 本のリスト版」のプログラムを,3 通りに書き直して 比べてください.
- 辞書で書き直す.何行短くなったか数える.
- 集合を使って,「登録されている色は何種類か」「
"あか"は登録済みか」を求める. - 辞書が並んだリスト(
[{"namae": …, "code": …}, …])で書き直す.どれがいちばん読みやすかったか,コメントに書く.
自由制作です.辞書を中心に据えた作品を作ってください. 題材は何でもかまいません.アイデアの例を挙げておきます.
- 絵辞書の完成版.果物・動物・乗り物など,自分で絵を 5 つ以上描いて登録する.
- お絵かきコマンド.
"まる""しかく""ほし"など,言葉を入力すると,その図形が画面に足されていく. - 県庁所在地クイズ・英単語クイズ.「県名 → 都市名」の辞書を作り,出題して正解数を数える.
- モールス信号.「文字 → 記号」の辞書を作り,入力された言葉を点と線の図で描く.
- 顔ジェネレータ.「目 → 描き方」「口 → 描き方」の辞書を作り,入力(または
random)で組み合わせて顔を作る.
条件:辞書を2 つ以上使うこと.
in か get() で
知らない入力に備えること.
for で辞書の中身をたどる場面を1 つ以上入れること.
まとめ
- リストは番号で引く入れ物,辞書は名前(キー)で引く入れ物.
- 辞書は
{"キー": 値, …}で作り,d[k]で取り出す.d[k] = vは,キーが無ければ新しく作る. - 無いキーを
d[k]で引くとKeyError.inで確かめるか,get()を使う. kaisu[k] = kaisu.get(k, 0) + 1は「数える」の定石.for k in d:はキー,for k, v in d.items():はキーと値の両方を取り出す.- 値にはリストも辞書も関数も入れられる.長い
elifの列は,たいてい辞書にできる. - キーにできるのは,あとから変わらないもの(文字列・数・タプル).
list・dict・set・tupleを使い分ける.迷ったら「やりたいことを日本語で言ってみる」.- 知らない命令は公式ドキュメントで調べる.暗記より調べ方.
次の回では,Python が最初から用意してくれている道具を見ていきます. 自分で書けば何十行にもなる処理が,呼ぶだけで済んでしまうことがあります. リストや辞書と組み合わせると,できることが一気に広がります.