コース進捗 コース目次 24レッスン中 24件を公開中
Pythonの基礎
データとコレクション
信頼できるプログラムを作る
オブジェクトでモデル化する
プロフェッショナルなPython
上級Python
辞書は名札付きの引き出し
リストは「位置0には何がある?」に答えます。辞書は「minutesという引き出しには何がある?」に答えます。各引き出しには一意なキーがあり、その中に1つの値があります。
-
キー
"topic"が名札 - 辞書 名札の引き出しを探す
-
値
"リスト"が中身
session = {
"topic": "リスト",
"minutes": 35,
"completed": True,
}
print(session["topic"])
print(session["minutes"])
リスト
35
現代のPythonでは辞書は挿入順を保ちますが、主な役目はキーによる検索です。番号付きの位置でも、自動的に並べ替えられた結果でもありません。
引き出しを開く、増やす、更新する、消す
角かっこは、必須のキーを読みます。代入なら、新しいキーを追加するか、既存キーの値を置き換えます。
progress = {"リスト": 1, "タプル": 1}
progress["辞書"] = 1
progress["リスト"] = 2
print(progress)
print("リスト" in progress)
print("集合" in progress)
{'リスト': 2, 'タプル': 1, '辞書': 1}
True
False
辞書に対するinが調べるのはキーであり、値ではありません。存在しないキーを角かっこで読むとKeyErrorです。キーがないことを想定しているなら、get()で意図した既定値を返せます。
scores = {"リスト": 0}
print(scores.get("リスト", 0))
print(scores.get("集合", 0))
print("リスト" in scores)
print("集合" in scores)
0
0
True
False
最初の0は保存済み、2つ目はキーがないという意味です。get()だけでは区別できません。del mapping[key]は存在するキーを削除し、mapping.pop(key)は削除した値も返します。キーがなければどちらも失敗するため、先に確認するか、pop()へ意図した既定値を渡します。
キーと値の両方が必要ならitems()でループします。
for topic, count in progress.items():
print(f"{topic}:{count}")
keys()はキー、values()は値を順に取り出します。
キーの形は安定していなければならない
辞書はハッシュを使って引き出しをすばやく探します。キーはハッシュ可能でなければなりません。つまり、使っている間にハッシュ値が変わらず、等しいキーどうしは同じハッシュ値を持つ必要があります。
-
文字列
"リスト" -
数値
42 -
固定タプル
(3, 5) -
変わるリスト
[3, 5]
文字列、整数、ハッシュ可能な部品だけを持つタプルは、よく使うキーです。変更可能なリスト、辞書、集合はハッシュ不可能なのでキーにできません。リストを中に持つタプルもハッシュ不可能です。辞書の値には、どのPythonオブジェクトでも入れられます。
カウンターでは、キーがないことが本当に「まだ0回」という意味なので、get(key, 0)がぴったりです。
counts = {}
for topic in ["リスト", "集合", "リスト"]:
counts[topic] = counts.get(topic, 0) + 1
print(counts)
{'リスト': 2, '集合': 1}
集合は同じシールを1枚だけ置くトレー
集合は、等しいハッシュ可能な要素を最大1つだけ持ちます。一意性、所属、集合どうしの関係を扱う道具です。意味のある表示順を保つ道具ではありません。
- 重複 同じシールが2枚来る
- 集合 等しいものは1枚にする
- 一意 あるかどうかが明確
tags = {"python", "入門", "python"}
empty_tags = set()
tags.add("コレクション")
tags.discard("ない値")
print(len(tags))
print("python" in tags)
print(type(empty_tags).__name__)
3
True
set
{}は空の辞書なので、空集合はset()で作ります。remove(x)はxがなければKeyError、discard(x)は「すでにない」状態も静かに受け入れます。
集合演算なら、関係を短く表せます。
planned = {"python", "コレクション", "テスト"}
covered = {"python", "コレクション", "復習"}
print((planned | covered) == {"python", "コレクション", "テスト", "復習"})
print((planned & covered) == {"python", "コレクション"})
print((planned - covered) == {"テスト"})
print((planned ^ covered) == {"テスト", "復習"})
print({"python"} <= covered)
5行ともTrueです。順に和集合、積集合、差集合、対称差、部分集合を確認しています。表示順ではなく、集合どうしを直接比較します。一意性と最初に出た順番の両方が必要なら、集合で「見たか」を覚え、リストで表示順を残します。
ミニ制作:学習トピック集計
topic_summary.pyを作ります。組み込みのコレクションだけで動く完成プログラムです。辞書で各記録とトピック回数を表し、集合で重複タグを除き、リストで最初に出た表示順を守ります。
sessions = [
{"topic": "リスト", "minutes": 35, "tags": ("python", "コレクション")},
{"topic": "辞書", "minutes": 40, "tags": ("python", "検索")},
{"topic": "リスト", "minutes": 25, "tags": ("python", "復習")},
]
topic_counts = {}
seen_tags = set()
tag_order = []
total = 0
for session in sessions:
topic = session["topic"]
total += session["minutes"]
topic_counts[topic] = topic_counts.get(topic, 0) + 1
for tag in session["tags"]:
if tag not in seen_tags:
seen_tags.add(tag)
tag_order.append(tag)
planned = {"python", "コレクション", "テスト"}
missing = planned - seen_tags
print(f"合計:{total}分")
for topic, count in topic_counts.items():
print(f"{topic}:{count}回")
print(f"タグ:{', '.join(tag_order)}")
print(f"未達成の予定タグ:{len(missing)}個")
print(f"回数は正しい:{topic_counts == {'リスト': 2, '辞書': 1}}")
python3 topic_summary.pyで実行し、次を確認します。
合計:100分
リスト:2回
辞書:1回
タグ:python, コレクション, 検索, 復習
未達成の予定タグ:1個
回数は正しい:True
境界の注意:ここでは、各記録に必要なキーがそろい、minutesが数値だと仮定します。欠けた項目や違う型の検証は第10章で扱います。
3つの小さなミッション
- 0の探偵。
{"リスト": 0}を使い、保存済みの0とキーの欠落が違うことをinで証明します。 - 単語カウンター。
['読む', '書く', '読む']を、辞書とget(word, 0)で数えます。 - 計画の比較。 予定と完了の集合を作り、共通するものと、まだ足りないものを求めます。
第8章へ進む準備
- 辞書の要素を読み、追加、更新し、意図を持って削除できる
- 辞書の
inがキーを調べると分かる - 欠けたキーと保存済みの0を区別できる
- キーと集合要素がハッシュ可能でなければならない理由を説明できる
set()で空集合を作り、一意な要素を保存できる- 表示順に頼らず、5つの基本的な集合関係を使える
- トピック集計を実行し、「回数は正しい:True」を確認できる
次章では、enumerate()、zip()、sorted()、読みやすい内包表記で、これらのコレクションを変換します。