Day 14:基礎総復習 ― CLI型ToDoアプリを作る
Day 14では、ここまで学んできた「変数・データ型・条件分岐・ループ・リスト・辞書・例外処理・ファイル操作・JSON」などを総動員して、 CLI(コマンドライン)型のToDoアプリを作っていきます。 タスク追加・一覧表示・削除・完了管理・JSON保存・エラー処理までを、一つのプログラムの中で体験することが目標です。
アプリの全体設計をイメージする
CLI型ToDoアプリの機能一覧
作るアプリの機能は次の通りです。
- タスク追加: やること(タスク)を登録する
- タスク一覧: 登録済みのタスクを一覧表示する
- タスク削除: 不要になったタスクを削除する
- 完了管理: タスクを「完了済み」にする
- JSON保存: タスク一覧をJSONファイルに保存・読み込みする
- エラー処理: 入力ミスやファイルエラーに丁寧に対応する
これらを、シンプルなメニュー形式のCLIアプリとしてまとめていきます。
データ構造を決める ― タスクをどう表現するか
タスク1件分の形
1つのタスクは、次のような情報を持つことにします。
id: タスクを一意に識別する番号title: タスクのタイトル(やることの内容)done: 完了しているかどうか(真偽値)
Pythonでは、これを辞書で表現します。
task = {
"id": 1,
"title": "Pythonの勉強をする",
"done": False, # まだ完了していない
}
Pythonタスク一覧の形
複数のタスクは、「辞書のリスト」として扱います。
tasks = [
{"id": 1, "title": "Pythonの勉強をする", "done": False},
{"id": 2, "title": "買い物に行く", "done": True},
]
Pythonこの形にしておくと、JSONへの保存・読み込みがとても自然になります。
JSON保存の基本 ― ファイルとのやり取り
JSONファイル名を決める
まず、タスクを保存するJSONファイル名を決めておきます。
TASK_FILE = "tasks.json"
PythonJSONから読み込む関数
アプリ起動時に、既存のタスクをJSONから読み込む関数を作ります。
import json
TASK_FILE = "tasks.json"
def load_tasks():
"""JSONファイルからタスク一覧を読み込む関数です。"""
try:
with open(TASK_FILE, "r", encoding="utf-8") as f:
tasks = json.load(f) # JSON → Pythonオブジェクト
# 読み込んだものがリストであることを確認します
if isinstance(tasks, list):
return tasks
else:
print("タスクファイルの形式が不正です。空の一覧として開始します。")
return []
except FileNotFoundError:
# ファイルがない場合は、初回起動とみなして空リストを返します
return []
except json.JSONDecodeError:
# JSONが壊れている場合
print("タスクファイルの内容が壊れています。空の一覧として開始します。")
return []
PythonJSONへ保存する関数
タスク一覧をJSONファイルに保存する関数も作ります。
def save_tasks(tasks):
"""タスク一覧をJSONファイルに保存する関数です。"""
try:
with open(TASK_FILE, "w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
except OSError as e:
print("タスクの保存中にエラーが発生しました。")
print(f"詳細: {e}")
Pythonここまでで、「タスク一覧 ↔ JSONファイル」の往復ができるようになります。
タスク追加機能を作る
新しいIDを決める
タスク追加時には、新しい id を決める必要があります。 既存のタスクの最大IDに1を足す形で決める関数を作ります。
def get_next_id(tasks):
"""次に使うタスクIDを返す関数です。"""
if not tasks:
return 1
max_id = max(task["id"] for task in tasks)
return max_id + 1
Pythonタスク追加関数
ユーザー入力を受けてタスクを追加する関数を作ります。
def add_task(tasks):
"""新しいタスクを追加する関数です。"""
title = input("追加するタスクの内容を入力してください: ").strip()
if not title:
print("タスク内容が空のため、追加をキャンセルしました。")
return
new_id = get_next_id(tasks)
task = {
"id": new_id,
"title": title,
"done": False,
}
tasks.append(task)
save_tasks(tasks)
print(f"タスクを追加しました(ID: {new_id})。")
Pythonここでは、
- 空入力をエラーとして扱い、追加をキャンセルしています。
- 追加後に
save_tasks()を呼び出して、JSONに保存しています。
タスク一覧表示機能を作る
タスク一覧を見やすく表示する関数を作ります。
def list_tasks(tasks):
"""タスク一覧を表示する関数です。"""
if not tasks:
print("現在登録されているタスクはありません。")
return
print("\n▼ タスク一覧")
print("--------------------")
for task in tasks:
status = "✔ 完了" if task["done"] else "・未完了"
print(f"ID: {task['id']} [{status}] {task['title']}")
print("--------------------")
Pythonここでは、
doneがTrueのタスクには「✔ 完了」、Falseには「・未完了」を表示しています。- ID・状態・タイトルを一目で分かる形にしています。
タスク削除機能を作る(エラー処理付き)
タスク削除では、「存在しないIDが指定される」可能性があります。 ここで、入力エラーに丁寧に対応するようにします。
def delete_task(tasks):
"""タスクを削除する関数です。"""
if not tasks:
print("削除できるタスクがありません。")
return
list_tasks(tasks)
id_text = input("削除したいタスクのIDを入力してください: ").strip()
if not id_text.isdigit():
print("IDは半角数字で入力してください。")
return
target_id = int(id_text)
# 指定されたIDのタスクを探します
for task in tasks:
if task["id"] == target_id:
tasks.remove(task)
save_tasks(tasks)
print(f"タスク(ID: {target_id})を削除しました。")
return
# ここまで来たということは、IDが見つからなかったということです
print(f"ID {target_id} のタスクは見つかりませんでした。")
Pythonここでは、
- タスクがない場合は早めに戻っています。
- ID入力が数字でない場合はエラーメッセージを出して終了しています。
- 指定IDが存在しない場合も、丁寧にメッセージを出しています。
完了管理機能を作る
タスクを「完了済み」にする機能を作ります。 削除と同様に、ID指定+エラー処理を行います。
def complete_task(tasks):
"""タスクを完了済みにする関数です。"""
if not tasks:
print("完了にできるタスクがありません。")
return
list_tasks(tasks)
id_text = input("完了にしたいタスクのIDを入力してください: ").strip()
if not id_text.isdigit():
print("IDは半角数字で入力してください。")
return
target_id = int(id_text)
for task in tasks:
if task["id"] == target_id:
if task["done"]:
print("このタスクはすでに完了済みです。")
else:
task["done"] = True
save_tasks(tasks)
print(f"タスク(ID: {target_id})を完了にしました。")
return
print(f"ID {target_id} のタスクは見つかりませんでした。")
Pythonここでは、
- すでに完了済みのタスクに対しては、その旨を伝えています。
- 完了状態の変更後に
save_tasks()を呼び出して、JSONに保存しています。
メインメニューとアプリ全体の流れ
最後に、これらの機能をメニュー形式でまとめたメイン関数を作ります。
def main():
"""CLI型ToDoアプリのメイン関数です。"""
tasks = load_tasks() # 起動時にタスク一覧を読み込みます
while True:
print("\n=== CLI型ToDoアプリ ===")
print("1: タスク一覧を表示する")
print("2: タスクを追加する")
print("3: タスクを削除する")
print("4: タスクを完了にする")
print("5: 終了する")
choice = input("番号を入力してください: ").strip()
if choice == "1":
list_tasks(tasks)
elif choice == "2":
add_task(tasks)
elif choice == "3":
delete_task(tasks)
elif choice == "4":
complete_task(tasks)
elif choice == "5":
print("CLI型ToDoアプリを終了します。")
break
else:
print("1〜5の番号を入力してください。")
if __name__ == "__main__":
main()
Pythonこのメイン関数により、
- 起動時にJSONからタスクを読み込み
- メニューから各機能を選択
- 操作のたびにJSONへ保存
という流れが実現されています。
Day 14のまとめ ― 「基礎をつないで一つのアプリにする」感覚
Day 14では、CLI型ToDoアプリを通して、
- 辞書とリストでデータ構造を設計すること
- JSONファイルへの保存・読み込みで「状態を持つアプリ」にすること
- 条件分岐・ループ・関数を組み合わせてメニュー型のCLIを作ること
- 入力エラーやファイルエラーに対して、例外処理やチェックで丁寧に対応すること
を一つの流れの中で体験していただきました。
ここまで来ると、「バラバラに学んできた基礎が、一つのアプリの中でつながる」という感覚が少し育っているはずです。 この感覚こそが、今後の90日間でより大きく・複雑なプログラムを作っていくうえでの土台になっていきます。
