6日目のゴール
6日目のテーマは
「JSON に“少しリッチなデータ構造”を持たせて、アプリの表現力を上げる」 ことです。
ここまでであなたはすでに、
JSON に複数データを保存できる
検索・更新・削除・フィルタ・ソートができる
コードを役割ごとに整理できる
というところまで来ています。
6日目では一歩進んで、
タスクに「優先度」や「締切日」を持たせる
JSON に“入れ子のデータ”を保存する
データの「形(構造)」を意識して設計する
という、「データ設計」の感覚を育てていきます。
今日の題材:ToDo を“ただの文字列”から“情報のかたまり”へ
タスクにどんな情報を持たせるか考える
今までのタスクは、こうでした。
{"title": "本を30分読む", "done": False}
Pythonこれはこれでシンプルで良いのですが、
現実の「やること」は、もっと情報を持っています。
例えば、こんな項目が考えられます。
タイトル(何をするか)
優先度(高・中・低)
締切日(いつまでにやるか)
メモ(補足情報)
完了したかどうか
これを Python の辞書で表現すると、こうなります。
task = {
"title": "本を30分読む",
"priority": "high",
"due": "2025-05-10",
"memo": "技術書を中心に読む",
"done": False
}
PythonJSON にすると、ほぼそのままです。
{
"title": "本を30分読む",
"priority": "high",
"due": "2025-05-10",
"memo": "技術書を中心に読む",
"done": false
}
ここで大事なのは、
「タスク=文字列」ではなく「タスク=情報のまとまり」
として扱い始めることです。
データ構造を変えるときの考え方
「既存のアプリにどう影響するか」を意識する
タスクの形を変えるときは、
次の二つを必ず意識します。
新しいタスクを作るとき、どの項目を必須にするか
既存の JSON ファイルとの互換性をどうするか
例えば、すでに tasks.json に
{"title": "メールを整理する", "done": true}
Pythonのようなデータが入っている状態で、
新しく priority や due を追加すると、
古いデータにはそのキーがありません。
このときに大事なのは、
「キーがない場合はどう扱うか」を決めておくことです。
例えば、
priority がなければ “normal” とみなす
due がなければ “未設定” と表示する
といったルールを決めておくと、
古いデータも壊さずに扱えます。
新しいタスクの形をコードに落とし込む
add_task を拡張する
タスク追加関数を、
新しい構造に合わせて書き直します。
def add_task(tasks):
title = input("タスク名: ")
priority = input("優先度(high / normal / low): ")
due = input("締切日(例: 2025-05-10。未設定なら空のまま): ")
memo = input("メモ(任意): ")
if priority not in ("high", "normal", "low"):
print("優先度が不正です。normal として扱います。")
priority = "normal"
if due == "":
due = None
if memo == "":
memo = None
task = {
"title": title,
"priority": priority,
"due": due,
"memo": memo,
"done": False
}
tasks.append(task)
print("タスクを追加しました。")
Pythonここで深掘りしたいポイントは三つあります。
一つ目は、「入力値をそのまま信じない」ことです。priority が "high" / "normal" / "low" 以外だったら、
自動的に "normal" にしてしまっています。
これは「データの一貫性」を守るための大事な考え方です。
二つ目は、「空文字を None に変換している」ことです。due や memo が空のままだと、
後で「未設定なのか、本当に空文字なのか」が分かりにくくなります。None にしておくと、「値がない」という意味がはっきりします。
三つ目は、「task の形をここで統一している」ことです。
アプリのどこからタスクを見ても、
必ず title / priority / due / memo / done が存在する、
という前提で話ができるようになります。
表示を“情報量のある形”に変える
show_tasks をリッチ表示にする
タスクの構造がリッチになったので、
表示もそれに合わせて変えます。
def show_tasks(tasks):
if not tasks:
print("タスクはありません。")
return
print("=== タスク一覧 ===")
for task in tasks:
mark = "✔" if task["done"] else "✗"
if task.get("priority") == "high":
priority_label = "[高]"
elif task.get("priority") == "low":
priority_label = "[低]"
else:
priority_label = "[中]"
due = task.get("due")
if due is None:
due_label = "(締切: なし)"
else:
due_label = f"(締切: {due})"
memo = task.get("memo")
if memo:
memo_label = f" - メモ: {memo}"
else:
memo_label = ""
print(f"{mark} {priority_label} {task['title']} {due_label}{memo_label}")
Pythonここでの重要ポイントを丁寧に見ていきます。
task.get("priority") を使っているのは、
古い JSON に priority がない場合でもエラーにしないためです。get は、キーがなければ None を返します。
priority_label では、"high" → [高]"low" → [低]
それ以外 → [中]
というふうに、人間に分かりやすいラベルに変換しています。
due が None のときは「締切なし」と表示し、
値があるときはその日付を表示します。
memo があるときだけ、メモを表示します。
ないときは何も表示しません。
このように、
「内部のデータ構造」と「画面に見せる形」を分ける
というのが、とても大事な考え方です。
優先度で並び替える
priority をソートキーに使う
優先度を持たせたら、
「高いものを上に表示したい」という欲が出てきます。
そのためのソート関数を作ります。
def sort_tasks_by_priority(tasks):
def priority_value(task):
p = task.get("priority", "normal")
if p == "high":
return 0
elif p == "normal":
return 1
else:
return 2
return sorted(tasks, key=priority_value)
Pythonここでのポイントは、
priority をそのままソートに使うのではなく、"high" → 0, "normal" → 1, "low" → 2
という「数値」に変換していることです。
ソートは「小さいものが先に来る」ので、0 → 1 → 2 の順、つまり
「高 → 中 → 低」の順に並びます。
task.get("priority", "normal") としているのは、
古いデータで priority がない場合に "normal" とみなすためです。
締切日で並び替える
文字列の日付でも「YYYY-MM-DD」ならそのままソートできる
締切日 due は "2025-05-10" のような文字列で持っています。
この形式(YYYY-MM-DD)なら、
実は文字列のままソートしても日付順になります。
def sort_tasks_by_due(tasks):
def due_value(task):
due = task.get("due")
if due is None:
return "9999-12-31"
return due
return sorted(tasks, key=due_value)
Pythonここでの工夫は、
締切がないタスクに "9999-12-31" を割り当てていることです。
これにより、
締切があるタスクが先
締切なしのタスクが後
という並びになります。
本格的にやるなら datetime モジュールを使いますが、
中級編の段階では「文字列の日付をうまく使う」という発想で十分です。
6日目のミニアプリ:リッチタスク JSON アプリ
全体像をまとめて見る
ここまでの内容を組み合わせると、
6日目のアプリはこんな形になります。
import json
import os
FILENAME = "tasks.json"
def load_tasks():
if not os.path.exists(FILENAME):
return []
with open(FILENAME, "r", encoding="utf-8") as f:
return json.load(f)
def save_tasks(tasks):
with open(FILENAME, "w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
def add_task(tasks):
title = input("タスク名: ")
priority = input("優先度(high / normal / low): ")
due = input("締切日(例: 2025-05-10。未設定なら空のまま): ")
memo = input("メモ(任意): ")
if priority not in ("high", "normal", "low"):
print("優先度が不正です。normal として扱います。")
priority = "normal"
if due == "":
due = None
if memo == "":
memo = None
task = {
"title": title,
"priority": priority,
"due": due,
"memo": memo,
"done": False
}
tasks.append(task)
print("タスクを追加しました。")
def find_task(tasks, title):
for task in tasks:
if task["title"] == title:
return task
return None
def update_task_done(tasks):
title = input("完了状態を変更するタスク名: ")
task = find_task(tasks, title)
if task is None:
print("タスクが見つかりません。")
return
done_text = input("完了なら1、未完了なら0: ")
task["done"] = (done_text == "1")
print("完了状態を更新しました。")
def show_tasks(tasks):
if not tasks:
print("タスクはありません。")
return
print("=== タスク一覧 ===")
for task in tasks:
mark = "✔" if task["done"] else "✗"
p = task.get("priority")
if p == "high":
priority_label = "[高]"
elif p == "low":
priority_label = "[低]"
else:
priority_label = "[中]"
due = task.get("due")
if due is None:
due_label = "(締切: なし)"
else:
due_label = f"(締切: {due})"
memo = task.get("memo")
if memo:
memo_label = f" - メモ: {memo}"
else:
memo_label = ""
print(f"{mark} {priority_label} {task['title']} {due_label}{memo_label}")
def sort_tasks_by_priority(tasks):
def priority_value(task):
p = task.get("priority", "normal")
if p == "high":
return 0
elif p == "normal":
return 1
else:
return 2
return sorted(tasks, key=priority_value)
def sort_tasks_by_due(tasks):
def due_value(task):
due = task.get("due")
if due is None:
return "9999-12-31"
return due
return sorted(tasks, key=due_value)
def main():
tasks = load_tasks()
print("JSONファイルから読み込みました。")
while True:
print("\n=== メニュー ===")
print("1: タスク追加")
print("2: 全タスク表示")
print("3: 優先度順で表示")
print("4: 締切日順で表示")
print("5: 完了状態を変更")
print("0: 終了")
choice = input("番号を選んでください: ")
if choice == "1":
add_task(tasks)
save_tasks(tasks)
elif choice == "2":
show_tasks(tasks)
elif choice == "3":
sorted_tasks = sort_tasks_by_priority(tasks)
show_tasks(sorted_tasks)
elif choice == "4":
sorted_tasks = sort_tasks_by_due(tasks)
show_tasks(sorted_tasks)
elif choice == "5":
update_task_done(tasks)
save_tasks(tasks)
elif choice == "0":
save_tasks(tasks)
print("終了します。")
break
else:
print("正しい番号を入力してください。")
if __name__ == "__main__":
main()
Python6日目で絶対に押さえてほしい本質
「JSONは、ただの保存形式ではなく“データ設計のキャンバス”」
今日の一番大事なポイントは、
タスクにどんな情報を持たせるか
その情報をどう表現するか(文字列・None・ラベルなど)
古いデータとの整合性をどう保つか
といった「データの形」を意識し始めたことです。
JSON は、
Python の dict / list をそのまま外に出したものです。
だからこそ、
構造を工夫すればするほど、
アプリの表現力も一緒に上がっていきます。
もし「タグをつけたい」「サブタスクを持たせたい」など
さらに複雑な構造を試したくなったら、
それはもう“データモデリング”の世界に足を踏み入れています。
7日目は、その集大成としてまとめていきましょう。

