Pythonで学ぶオブジェクト指向プログラミング:タスク管理アプリの解説

はじめに

今回は、Pythonのオブジェクト指向プログラミングを用いた「タスク管理アプリ」のサンプルコードを解説します。このプログラムでは、継承ポリモーフィズム、**ファイル操作(JSON形式)**を使って、以下の機能を実現しています。

  • タスクの追加、削除、検索、編集
  • 優先度付きタスク、期限付きタスクの管理
  • タスクの保存と読み込み(JSONファイルを使用)
  • コマンドラインインターフェース(CLI)

Pythonのオブジェクト指向の基本から、実際のアプリケーションへの応用までを学べる内容になっています。

プログラムの全体像

import json
from datetime import datetime

# 基底クラス:タスク
class Task:
    """タスクを表す基本クラス"""
    def __init__(self, name, details):
        self.name = name  # タスクの名前
        self.details = details  # タスクの詳細

    def display(self):
        """タスク情報を表示する"""
        return f"[タスク] 名前: {self.name}, 詳細: {self.details}"

# 派生クラス:優先度付きタスク
class PriorityTask(Task):
    """優先度付きタスクを表すクラス"""
    def __init__(self, name, details, priority):
        super().__init__(name, details)
        self.priority = priority  # タスクの優先度

    def display(self):
        """タスク情報を表示する(優先度付き)"""
        return f"[優先度付きタスク] 名前: {self.name}, 詳細: {self.details}, 優先度: {self.priority}"

# 派生クラス:期限付きタスク
class DeadlineTask(Task):
    """期限付きタスクを表すクラス"""
    def __init__(self, name, details, deadline):
        super().__init__(name, details)
        self.deadline = deadline  # タスクの期限

    def display(self):
        """タスク情報を表示する(期限付き)"""
        return f"[期限付きタスク] 名前: {self.name}, 詳細: {self.details}, 期限: {self.deadline}"

# タスク管理クラス
class TaskManager:
    """タスクを管理するクラス"""
    def __init__(self):
        self.tasks = []  # タスクのリスト

    def add_task(self, task):
        """タスクを追加する"""
        self.tasks.append(task)
        print(f"タスクを追加しました: {task.display()}")

    def remove_task(self, name):
        """タスクを名前で削除する"""
        for task in self.tasks:
            if task.name == name:
                self.tasks.remove(task)
                print(f"タスクを削除しました: {task.display()}")
                return
        print("該当するタスクが見つかりません。")

    def search_task(self, name):
        """タスクを名前で検索する"""
        for task in self.tasks:
            if task.name == name:
                print(f"タスクが見つかりました: {task.display()}")
                return task
        print("該当するタスクが見つかりません。")
        return None

    def edit_task(self, name, new_details):
        """タスクの詳細を編集する"""
        task = self.search_task(name)
        if task:
            task.details = new_details
            print(f"タスクを編集しました: {task.display()}")

    def list_tasks(self):
        """全タスクを表示する"""
        if not self.tasks:
            print("タスクはありません。")
        for task in self.tasks:
            print(task.display())

    def save_to_file(self, filename="tasks.json"):
        """タスクをJSONファイルに保存する"""
        with open(filename, "w", encoding="utf-8") as file:
            json.dump([self._task_to_dict(task) for task in self.tasks], file, ensure_ascii=False, indent=4)
        print(f"タスクをファイルに保存しました: {filename}")

    def load_from_file(self, filename="tasks.json"):
        """JSONファイルからタスクを読み込む"""
        try:
            with open(filename, "r", encoding="utf-8") as file:
                tasks_data = json.load(file)
                self.tasks = [self._dict_to_task(data) for data in tasks_data]
            print(f"ファイルからタスクを読み込みました: {filename}")
        except FileNotFoundError:
            print("ファイルが見つかりません。新しいリストを作成します。")

    def _task_to_dict(self, task):
        """タスクオブジェクトを辞書形式に変換する(内部用)"""
        if isinstance(task, PriorityTask):
            return {"type": "PriorityTask", "name": task.name, "details": task.details, "priority": task.priority}
        elif isinstance(task, DeadlineTask):
            return {"type": "DeadlineTask", "name": task.name, "details": task.details, "deadline": task.deadline}
        else:
            return {"type": "Task", "name": task.name, "details": task.details}

    def _dict_to_task(self, data):
        """辞書形式をタスクオブジェクトに変換する(内部用)"""
        if data["type"] == "PriorityTask":
            return PriorityTask(data["name"], data["details"], data["priority"])
        elif data["type"] == "DeadlineTask":
            return DeadlineTask(data["name"], data["details"], data["deadline"])
        else:
            return Task(data["name"], data["details"])


# CLIインターフェース
def main():
    manager = TaskManager()
    manager.load_from_file()

    while True:
        print("\nタスク管理アプリ")
        print("1. タスクを追加")
        print("2. タスクを削除")
        print("3. タスクを検索")
        print("4. タスクを編集")
        print("5. 全タスクを表示")
        print("6. タスクを保存")
        print("7. 終了")
        choice = input("選択してください: ")

        if choice == "1":
            name = input("タスク名: ")
            details = input("タスク詳細: ")
            print("1. 通常タスク\n2. 優先度付きタスク\n3. 期限付きタスク")
            task_type = input("タスクタイプを選択してください: ")
            if task_type == "1":
                task = Task(name, details)
            elif task_type == "2":
                priority = input("優先度を入力してください: ")
                task = PriorityTask(name, details, priority)
            elif task_type == "3":
                deadline = input("期限を入力してください (YYYY-MM-DD): ")
                try:
                    datetime.strptime(deadline, "%Y-%m-%d")  # 期限の形式を確認
                    task = DeadlineTask(name, details, deadline)
                except ValueError:
                    print("不正な日付形式です。タスクを追加できませんでした。")
                    continue
            else:
                print("無効なタスクタイプです。")
                continue
            manager.add_task(task)
        elif choice == "2":
            name = input("削除するタスク名: ")
            manager.remove_task(name)
        elif choice == "3":
            name = input("検索するタスク名: ")
            manager.search_task(name)
        elif choice == "4":
            name = input("編集するタスク名: ")
            new_details = input("新しい詳細: ")
            manager.edit_task(name, new_details)
        elif choice == "5":
            manager.list_tasks()
        elif choice == "6":
            manager.save_to_file()
        elif choice == "7":
            manager.save_to_file()
            print("終了します。")
            break
        else:
            print("無効な選択です。")

if __name__ == "__main__":
    main()

プログラムの全体構成

このプログラムは以下の4つのパートで構成されています。

  1. Task, PriorityTask, DeadlineTask クラス
    • タスクの基本情報を管理するクラス群
  2. TaskManager クラス
    • タスクの追加、削除、検索、編集、保存、読み込みを管理
  3. JSON ファイル操作
    • タスクをJSON形式で保存、読み込み
  4. CLI (Command Line Interface)
    • コマンドラインから操作できるユーザーインターフェース

クラス設計

1. Task クラス

Task クラスは 基底クラス であり、すべてのタスクの基本情報を管理します。

class Task:
    """タスクを表す基本クラス"""
    def __init__(self, name, details):
        self.name = name  # タスクの名前
        self.details = details  # タスクの詳細

    def display(self):
        """タスク情報を表示する"""
        return f"[タスク] 名前: {self.name}, 詳細: {self.details}"

ポイント

  • __init__ メソッドを使用して、名前(name)詳細(details) を初期化
  • display() メソッドでタスクの情報を表示

2. PriorityTask クラス

PriorityTask クラスは、Task クラスを継承して 優先度付きタスク を表現しています。

class PriorityTask(Task):
    """優先度付きタスクを表すクラス"""
    def __init__(self, name, details, priority):
        super().__init__(name, details)
        self.priority = priority  # タスクの優先度

    def display(self):
        """タスク情報を表示する(優先度付き)"""
        return f"[優先度付きタスク] 名前: {self.name}, 詳細: {self.details}, 優先度: {self.priority}"

ポイント

  • 継承 を使用して Task クラスのプロパティを引き継いでいます。
  • super().__init__(name, details) で親クラスのコンストラクタを呼び出しています。
  • 優先度を表す priority 属性を追加。

3. DeadlineTask クラス

DeadlineTask クラスは、Task クラスを継承して 期限付きタスク を表現しています。

class DeadlineTask(Task):
    """期限付きタスクを表すクラス"""
    def __init__(self, name, details, deadline):
        super().__init__(name, details)
        self.deadline = deadline  # タスクの期限

    def display(self):
        """タスク情報を表示する(期限付き)"""
        return f"[期限付きタスク] 名前: {self.name}, 詳細: {self.details}, 期限: {self.deadline}"

ポイント

  • 期限を表す deadline 属性を追加。
  • display() メソッドで期限を含めた情報を表示。

4. TaskManager クラス

TaskManager クラスは、タスクの管理を担当する 管理クラス です。

class TaskManager:
    """タスクを管理するクラス"""
    def __init__(self):
        self.tasks = []  # タスクのリスト

機能

  • 追加: add_task() メソッド
  • 削除: remove_task() メソッド
  • 検索: search_task() メソッド
  • 編集: edit_task() メソッド
  • 表示: list_tasks() メソッド
  • 保存: save_to_file() メソッド
  • 読み込み: load_from_file() メソッド

JSONを使ったファイル操作

保存機能

def save_to_file(self, filename="tasks.json"):
    """タスクをJSONファイルに保存する"""
    with open(filename, "w", encoding="utf-8") as file:
        json.dump([self._task_to_dict(task) for task in self.tasks], file, ensure_ascii=False, indent=4)
    print(f"タスクをファイルに保存しました: {filename}")
  • json.dump() を使用してタスクを JSON 形式で保存します。
  • _task_to_dict() メソッドでタスクオブジェクトを辞書形式に変換しています。

読み込み機能

def load_from_file(self, filename="tasks.json"):
    """JSONファイルからタスクを読み込む"""
    try:
        with open(filename, "r", encoding="utf-8") as file:
            tasks_data = json.load(file)
            self.tasks = [self._dict_to_task(data) for data in tasks_data]
        print(f"ファイルからタスクを読み込みました: {filename}")
    except FileNotFoundError:
        print("ファイルが見つかりません。新しいリストを作成します。")
  • json.load() を使用して JSON ファイルからタスクを読み込みます。
  • _dict_to_task() メソッドで辞書をタスクオブジェクトに戻しています。

コマンドラインインターフェース (CLI)

def main():
    manager = TaskManager()
    manager.load_from_file()

    while True:
        print("\nタスク管理アプリ")
        print("1. タスクを追加")
        print("2. タスクを削除")
        print("3. タスクを検索")
        print("4. タスクを編集")
        print("5. 全タスクを表示")
        print("6. タスクを保存")
        print("7. 終了")
        choice = input("選択してください: ")
  • ユーザーがタスクを操作するためのインターフェースを提供しています。
  • コマンドラインからタスクの追加、削除、検索、編集、保存、読み込みが可能。

まとめ

  • オブジェクト指向プログラミングの 継承ポリモーフィズム を活用
  • Task, PriorityTask, DeadlineTaskクラス設計 を応用
  • JSONファイル操作 によりデータの保存と読み込みを実現
  • CLIインターフェース で操作性を向上

Pythonのオブジェクト指向設計を理解するのに最適な例です。ぜひ、コードを動かしながら学習してみてください。