13日目のゴールとテーマ
13日目のテーマは「コードを“モジュール化”して、ちゃんとしたプロジェクト構成にする」です。
ここまでで、クラスも関数も使って、タスク管理アプリをかなり育ててきました。
でも、まだひとつ大きな課題が残っています。
それは「全部1ファイルに書いていて、だんだんゴチャゴチャしてきた」という問題です。
今日はここを一気に整理していきます。
クラスを別ファイルに分ける。
自作モジュールを import して使う。
「プロジェクトとしての形」を意識してコードを並べる。
この感覚をつかむと、「練習用スクリプト」から「ちゃんとしたアプリ」に一段階進みます。
なぜファイルを分ける必要があるのか
1ファイルに全部書く限界
最初のうちは、1つのファイルに全部書いても問題ありません。
行数も少ないし、どこに何があるかもすぐ分かります。
でも、クラスや関数が増えてくると、こうなりがちです。
上のほうにクラス定義があって、その下に関数がたくさんあって、一番下に main がある。
どこを直せばいいのか探すのに時間がかかる。
別のアプリでも使いたいクラスがあるのに、コピペするしかない。
ここで必要になるのが「モジュール化」です。
役割ごとにファイルを分けて、「このファイルにはこれが入っている」と決めていきます。
モジュールとは何かをもう一度整理する
「Pythonファイル1つが、そのままモジュールになる」
Pythonでは、拡張子が .py のファイル1つが、そのまま「モジュール」です。
例えば、task.py というファイルを作れば、それは task というモジュールになります。
標準ライブラリの random や datetime もモジュールでした。
それと同じように、自分で作ったファイルも import して使えます。
イメージとしてはこうです。
task.py に Task クラスを書く。
task_manager.py に TaskManager クラスを書く。
main.py にメニューやアプリの流れを書く。
そして、main.py から他のファイルを import して使う。
これが今日やりたいことです。
Task クラスを task.py に切り出す
クラス専用のファイルを作る
まずは Task クラスを、専用のファイルに移します。task.py というファイルを作って、次のように書きます。
import datetime
class Task:
def __init__(self, name, deadline):
self.name = name
self.deadline = deadline
def remaining_days(self):
today = datetime.date.today()
diff = self.deadline - today
return diff.days
def status_text(self):
days = self.remaining_days()
deadline_text = self.deadline.strftime("%Y/%m/%d")
if days > 0:
return "締切: " + deadline_text + "(あと " + str(days) + " 日)"
elif days == 0:
return "締切: " + deadline_text + "(今日が締切!)"
else:
return "締切: " + deadline_text + "(期限切れ: " + str(-days) + " 日過ぎ)"
Pythonここでのポイントは、Task クラスが「このファイルの主役」になっていることです。
Task に関する変更や追加は、基本的にこのファイルだけ見ればよくなります。
TaskManager クラスを task_manager.py に切り出す
管理者クラスも専用ファイルにする
次に、TaskManager を別ファイルにします。task_manager.py を作って、こう書きます。
import datetime
from task import Task
class TaskManager:
def __init__(self):
self.tasks = []
def add(self, task):
self.tasks.append(task)
def all(self):
return self.tasks
def delete(self, index):
if 0 <= index < len(self.tasks):
del self.tasks[index]
return True
return False
def save(self, filename):
with open(filename, "w", encoding="utf-8") as file:
for task in self.tasks:
line = task.name + "," + task.deadline.isoformat() + "\n"
file.write(line)
def load(self, filename):
self.tasks = []
try:
with open(filename, "r", encoding="utf-8") as file:
for line in file:
line = line.strip()
if line == "":
continue
parts = line.split(",")
if len(parts) != 2:
continue
name = parts[0]
date_text = parts[1]
try:
year_str, month_str, day_str = date_text.split("-")
year = int(year_str)
month = int(month_str)
day = int(day_str)
deadline = datetime.date(year, month, day)
except Exception:
continue
task = Task(name, deadline)
self.tasks.append(task)
except FileNotFoundError:
self.tasks = []
Pythonここでの重要ポイントを深掘りします。
最初に from task import Task と書いています。
これは「同じフォルダにある task.py から Task クラスを読み込む」という意味です。
標準ライブラリと同じように、自作のモジュールも import できます。
TaskManager の中では、Task クラスを普通に使っています。Task(name, deadline) で新しいタスクを作り、リストに追加しています。
Task の中身を知らなくても、「Task は name と deadline を受け取る」という前提だけで使えます。
main.py を「アプリの入口」にする
メニューとユーザーとの対話だけを書く
最後に、アプリの入口となる main.py を作ります。
ここには、メニュー表示とユーザー入力、そして TaskManager の呼び出しだけを書きます。
from task_manager import TaskManager
import datetime
def print_menu():
print("=== タスク管理アプリ 13日目バージョン ===")
print("1: タスクを追加する")
print("2: タスク一覧を表示する")
print("3: タスクを削除する")
print("4: タスクを保存する")
print("5: タスクを読み込む")
print("0: 終了する")
def input_menu_number():
while True:
text = input("番号を選んでください: ")
try:
value = int(text)
except ValueError:
print("数字で入力してください。")
continue
if value not in [0, 1, 2, 3, 4, 5]:
print("0〜5の番号を入力してください。")
continue
return value
def input_date():
text = input("締切日を入力してください(YYYY-MM-DD): ")
try:
year_str, month_str, day_str = text.split("-")
year = int(year_str)
month = int(month_str)
day = int(day_str)
return datetime.date(year, month, day)
except Exception:
print("日付の形式が正しくありません。")
return None
def main():
manager = TaskManager()
filename = "tasks.txt"
manager.load(filename)
while True:
print_menu()
number = input_menu_number()
if number == 0:
print("アプリを終了します。")
break
elif number == 1:
name = input("タスク名を入力してください: ")
if name == "":
print("タスク名が空です。追加をキャンセルします。")
continue
deadline = input_date()
if deadline is None:
print("タスクの追加をキャンセルします。")
continue
from task import Task
task = Task(name, deadline)
manager.add(task)
print("タスクを追加しました。")
elif number == 2:
tasks = manager.all()
if len(tasks) == 0:
print("タスクは登録されていません。")
else:
print("=== タスク一覧 ===")
for i, task in enumerate(tasks, start=1):
print(str(i) + ". " + task.name + " → " + task.status_text())
elif number == 3:
index_text = input("削除するタスクの番号を入力してください: ")
try:
index = int(index_text) - 1
except ValueError:
print("数字で入力してください。")
continue
if manager.delete(index):
print("タスクを削除しました。")
else:
print("その番号のタスクは存在しません。")
elif number == 4:
manager.save(filename)
print("タスクを保存しました。")
elif number == 5:
manager.load(filename)
print("タスクを読み込みました。")
if __name__ == "__main__":
main()
Pythonここでの深掘りポイントは、「main.py は“アプリの流れ”だけを書いている」ということです。
Task の中身は task.py にある。
TaskManager の中身は task_manager.py にある。
main.py は、それらを組み合わせて「どう動くか」を決めている。
この分担ができると、どこを読めば何が分かるかが、はっきりします。
自作モジュールを import するときの注意点
ファイルの置き場所と名前
自作モジュールを import するときに、いくつか気をつけるポイントがあります。
まず、同じフォルダに置くこと。
task.py、task_manager.py、main.py を同じディレクトリに置いておけば、from task import Task や from task_manager import TaskManager がそのまま動きます。
次に、ファイル名とモジュール名が一致していること。
task.py ならモジュール名は task。
task_manager.py ならモジュール名は task_manager。
import するときは拡張子 .py を書かないことに注意してください。
そして、モジュール名にスペースや日本語は使わないこと。
英小文字とアンダースコアだけにしておくと、トラブルが少なくなります。
モジュール化の一番大事な効果
「頭を切り替えやすくなる」
ファイルを分ける一番のメリットは、「考える範囲を狭くできること」です。
Task を直したいときは task.py だけを開けばいい。
タスクの保存形式を変えたいときは task_manager.py を見ればいい。
メニューの文言を変えたいときは main.py だけ触ればいい。
1ファイルに全部詰め込んでいると、
何かを直すたびに「他に影響しないかな」と不安になります。
モジュール化して役割を分けておくと、
「この変更はこのファイルの責任範囲だ」と割り切りやすくなります。
これは、実務の現場でもものすごく大事な感覚です。
13日目で一番大事な感覚
「ファイルを分けるのは、“アプリの地図”を描くこと」
今日あなたに持ってほしい感覚はこれです。
モジュール化は、単にファイルを増やす作業ではありません。
アプリの中に「地図」を描く行為です。
Task はここ。
TaskManager はここ。
アプリの入口はここ。
こうやって地図が描けていると、
自分も他人も、そのアプリの中を迷わず歩けるようになります。
13日目のまとめ
今日のキーポイントを短く整理すると、こうなります。
Pythonファイル1つが、そのまま「モジュール」になる。
自作モジュールは from ファイル名 import クラス名 で読み込める。
Task クラスを task.py に、TaskManager を task_manager.py に分けると、責任範囲がはっきりする。
main.py には「アプリの流れ」と「ユーザーとの対話」だけを書くと読みやすい。
モジュール化は、「どこに何があるか」というアプリの地図を作る行為。
もし余裕があれば、次のようなチャレンジをしてみてください。
入力まわり(メニュー番号や日付入力)を、input_utils.py のような別モジュールに切り出す。
Task クラスに「完了フラグ」を追加して、その状態もファイル保存・読み込みに含める。
別の小さなアプリでも Task や TaskManager を再利用してみる。
ここまで来ると、あなたのコードはもう「学習用スクリプト」ではなく、
立派な「小さなプロジェクト」です。
14日目は、このプロジェクトを“総仕上げ”の気持ちで、もう一段階だけ磨いていきましょう。
