基礎から学ぶPython入門 90日コース | Python基礎 - Day 14:基礎総復習

Python 90日で身につけるPython
スポンサーリンク
スポンサーリンク

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"
Python

JSONから読み込む関数

アプリ起動時に、既存のタスクを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 []
Python

JSONへ保存する関数

タスク一覧を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

ここでは、

  • doneTrue のタスクには「✔ 完了」、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日間でより大きく・複雑なプログラムを作っていくうえでの土台になっていきます。

タイトルとURLをコピーしました