10日目のゴールとテーマ
10日目のテーマは「メニュー付きの“ちゃんとしたコンソールアプリ”を組み立てる」です。
ここまでで、関数・リスト・辞書・ファイル・例外・標準ライブラリと、かなりのパーツを学んできました。
今日はそれらを「バラバラの練習」ではなく、
ひとつのアプリとしてまとめ上げる感覚をつかんでもらいます。
目標はこうです。
メニューを表示して、ユーザーに「やりたいこと」を選んでもらう
選ばれた番号に応じて、対応する処理を呼び出す
アプリ全体の“流れ”を意識してコードを組み立てる
テーマアプリは、これまで何度か出てきた「タスク管理アプリ」を、
メニュー付きの“それっぽい形”に進化させます。
メニュー付きアプリの基本イメージ
「やりたいことを番号で選ぶ」スタイル
まずは、頭の中にイメージを作りましょう。
コンソールで動くアプリに、こんなメニューを出したいとします。
=== タスク管理アプリ ===
1: タスクを追加する
2: タスク一覧を表示する
3: タスクを保存する
4: タスクを読み込む
0: 終了する
番号を選んでください:
ユーザーは 1〜4 または 0 を入力します。
アプリは、その番号に応じて処理を切り替えます。
この「メニュー → 入力 → 分岐 → 処理 → またメニュー」というループが、
コンソールアプリの基本パターンです。
メニューを表示する関数を作る
「表示だけを担当する関数」に切り出す
まずは、メニュー表示を関数にしてしまいましょう。
def print_menu():
print("=== タスク管理アプリ 10日目バージョン ===")
print("1: タスクを追加する")
print("2: タスク一覧を表示する")
print("3: タスクを保存する")
print("4: タスクを読み込む")
print("0: 終了する")
Pythonこの関数は「メニューを表示するだけ」です。
ここに「入力」や「処理」は書きません。
こうやって「役割を1つに絞った関数」を作ると、
あとからメニューの文言を変えたいときも、この関数だけ見ればよくなります。
メニュー番号を入力させる関数
入力バリデーションを入れて「変な番号」を弾く
次に、「メニュー番号を入力してもらう」関数を作ります。
ここで、8日目にやった「入力バリデーション」の考え方を使います。
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]:
print("0〜4の番号を入力してください。")
continue
return value
Python流れを丁寧に追います。
まず、while True で「正しい番号が入るまでくり返す」ループを作る。
毎回、文字列として入力を受け取る。
int に変換を試みて、数字でなければ「数字で入力してください」と言ってやり直し。
数字だったら、0〜4のどれかかどうかをチェックする。
範囲外なら「0〜4の番号を」と言ってやり直し。
問題なければ、その番号を return して関数を終わる。
これで、「変な入力でアプリが落ちる」ことはなくなります。
メニュー番号の入力は、アプリの“入口”なので、ここを丁寧にしておくと全体が安定します。
タスクのデータ構造を決める
「1件分は辞書」「全体はリスト」のおさらい
タスク管理アプリの「タスク1件分」は、こういう情報を持たせることにします。
タスク名(文字列)
締切日(datetime.date)
これを辞書で表現します。
task = {
"name": "レポートを書く",
"deadline": datetime.date(2026, 4, 10)
}
Python複数のタスクは、これをリストに入れて管理します。
tasks = [
{"name": "レポートを書く", "deadline": datetime.date(2026, 4, 10)},
{"name": "買い物に行く", "deadline": datetime.date(2026, 3, 30)}
]
Pythonこの「辞書のリスト」は、5〜9日目で何度も出てきた形です。
もうかなり馴染んできたはずです。
タスクを追加する関数
入力 → バリデーション → 辞書にしてリストへ
タスクを1件追加する処理を、関数にします。
ここでは、9日目で作った parse_date の考え方も使います。
import datetime
def parse_date(text):
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:
return None
def add_task(tasks):
name = input("タスク名を入力してください: ")
if name == "":
print("タスク名が空です。追加をキャンセルします。")
return
date_text = input("締切日を入力してください(YYYY-MM-DD): ")
deadline = parse_date(date_text)
if deadline is None:
print("日付の形式が正しくありません。タスクの追加をキャンセルします。")
return
task = {"name": name, "deadline": deadline}
tasks.append(task)
print("タスクを追加しました。")
Pythonここでの重要ポイントを深掘りします。
add_task は「tasks リストを受け取って、その中に1件追加する」関数。
タスク名が空だったら、「追加しない」という判断をして return している。
締切日がパースできなかった場合も、「追加しない」という判断をしている。
成功したときだけ、辞書を作って tasks.append(task) している。
このように、「どんなときに追加するか」「どんなときに追加しないか」を
コードの中でハッキリさせておくと、アプリの挙動が読みやすくなります。
タスク一覧を表示する関数
今日との日数差も一緒に出してあげる
タスク一覧を表示する関数を作ります。
9日目の「締切まであと何日か」を再利用します。
def print_tasks(tasks):
today = datetime.date.today()
print("=== タスク一覧 ===")
if len(tasks) == 0:
print("タスクは登録されていません。")
return
for i, task in enumerate(tasks, start=1):
name = task["name"]
deadline = task["deadline"]
diff = deadline - today
days = diff.days
deadline_text = deadline.strftime("%Y/%m/%d")
if days > 0:
status = "締切まであと " + str(days) + " 日"
elif days == 0:
status = "今日が締切!"
else:
status = "期限切れ(" + str(-days) + " 日過ぎ)"
print(str(i) + ". " + name + "(締切: " + deadline_text + ") → " + status)
Pythonここでのポイントは、
enumerate(tasks, start=1) を使って、「1番、2番…」と番号付きで表示していること。
締切日と今日の日付の差から、「あと何日か」「期限切れか」を計算していること。
タスクが1件もない場合は、早めに return していること。
この関数は「表示だけ」を担当します。
削除や編集は、今日はやりませんが、
番号付きで表示しておくと、あとから「3番を削除」などの機能を足しやすくなります。
タスクをファイルに保存・読み込みする関数
7日目・9日目の内容を「タスク用」に再利用する
タスクをファイルに保存する関数と、読み込む関数を用意します。
形式はシンプルに、「1行1タスク」「カンマ区切り」でいきます。
def save_tasks_to_file(tasks, filename):
with open(filename, "w", encoding="utf-8") as file:
for task in tasks:
name = task["name"]
deadline = task["deadline"]
line = name + "," + deadline.isoformat() + "\n"
file.write(line)
print("タスクをファイルに保存しました。")
def load_tasks_from_file(filename):
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]
deadline = parse_date(date_text)
if deadline is None:
continue
task = {"name": name, "deadline": deadline}
tasks.append(task)
print("タスクをファイルから読み込みました。")
except FileNotFoundError:
print("ファイルが見つかりませんでした。新しいタスク一覧を作ります。")
tasks = []
return tasks
Pythonここでの重要ポイントを整理します。
保存側では、deadline.isoformat() を使って日付を "YYYY-MM-DD" 形式の文字列にしている。
読み込み側では、その文字列を parse_date で date 型に戻している。
ファイルがない場合はエラーにせず、「空のタスク一覧」として扱っている。
おかしな行(カンマがない、日付がおかしいなど)はスキップしている。
これで、「アプリを終了してもタスクが残る」状態になります。
メインループを組み立てる
「メニュー → 入力 → 分岐 → 処理 → 戻る」の流れ
ここまで作った部品を、いよいよ「メインループ」に組み込みます。
FILENAME = "tasks.txt"
def main():
tasks = load_tasks_from_file(FILENAME)
while True:
print_menu()
number = input_menu_number()
if number == 0:
print("アプリを終了します。")
break
elif number == 1:
add_task(tasks)
elif number == 2:
print_tasks(tasks)
elif number == 3:
save_tasks_to_file(tasks, FILENAME)
elif number == 4:
tasks = load_tasks_from_file(FILENAME)
else:
print("想定外の番号です。")
if __name__ == "__main__":
main()
Pythonこの部分が、今日の一番おいしいところです。
流れを言葉で追ってみましょう。
最初に load_tasks_from_file で、前回までのタスクを読み込む。
while True で「メニューを何度でも表示する」ループに入る。
毎回 print_menu でメニューを表示し、input_menu_number で番号を入力してもらう。
番号に応じて、if / elif で処理を分岐する。
0 なら break でループを抜けて終了。
1 なら add_task でタスクを追加。
2 なら print_tasks で一覧表示。
3 なら save_tasks_to_file で保存。
4 なら load_tasks_from_file で再読み込み(外でファイルを編集した場合などを想定)。
そして、最後の
if __name__ == "__main__":
main()
Pythonは、「このファイルが“直接実行されたときだけ” main() を呼ぶ」というお約束です。
将来、このファイルを他のファイルから import して使うときに、
勝手に main が動き出さないようにするための仕組みです。
今の段階では、「Pythonのファイルの最後にこう書いておくと、
“ここがスタート地点です”と決められる」と理解しておけば十分です。
10日目で一番大事な感覚
「コードが“アプリの流れ”として読めるようになる」
今日あなたに持ってほしい感覚はこれです。
メニューを表示する関数
番号を入力させる関数
タスクを追加する関数
タスクを表示する関数
タスクを保存・読み込みする関数
それらを呼び出す main 関数
こうやって、「役割ごとに関数を分けておいて、
メインループで“物語”としてつなぐ」という感覚です。
コードを上から読んだときに、
起動したら前回のタスクを読み込んで
メニューを出して
ユーザーの選択に応じて処理して
0 が選ばれたら終わる
というストーリーが見えるかどうか。
ここまで来ると、あなたはもう「文法を知っている人」ではなく、
「アプリの流れを設計できる人」の側に足を踏み入れています。
10日目のまとめ
今日のキーポイントを短く整理するとこうなります。
メニュー付きコンソールアプリは、「メニュー表示 → 入力 → 分岐 → 処理 → ループ」の形が基本。
メニュー表示と番号入力は、それぞれ専用の関数に分けると読みやすい。
タスクは「辞書1件+リスト全体」で管理し、締切は datetime.date で持つ。
ファイル保存・読み込みは、7・9日目のパターンをタスク用に応用できる。
main 関数と if __name__ == "__main__": で、「ここがアプリの入口」と決められる。
もし余裕があれば、今日のタスク管理アプリに次の機能を足してみてください。
特定のタスクを削除する(番号を指定して消す)
締切が近いタスクだけを表示するメニュー項目を追加する
タスクに「メモ」や「優先度」を追加して、表示内容をリッチにする
ここから先は、もう「何を作るか」の世界です。
土台は十分できているので、あなたの生活や仕事で「これ自動化したいな」と思うものを、
少しずつこのスタイルでアプリにしていきましょう。
