前提
本日のお題
2. コマンドライン Todo リスト
何を作る?
python todo.py add "買い物" のようにタスク追加 / 一覧 / 削除できる簡単 CLI。
学べること
-
argparseでのコマンドライン引数処理 - JSON / テキストを使った簡易データ保存
- 関数分割・小さなアプリ設計
面白いところ
- 自分の日常でそのまま使える
- コマンドを増やして「完了済み」「締切」などに拡張していける
回答
コード
02_todo_cli.py
import argparse
import json
import datetime
DB_JSON_PATH = "02_db.json"
def add_item(todo_items, item):
new_todo_items = todo_items.copy()
new_todo_items.append({
"item": item,
"created_at": str(datetime.datetime.now())
})
return new_todo_items
def show_list(todo_items):
for item_dict in todo_items:
print(item_dict)
def delete_item(todo_items, item):
new_todo_items = todo_items.copy()
for i, item_dict in enumerate(todo_items):
it, _ = item_dict.values()
if it == item:
new_todo_items.pop(i)
break
return new_todo_items
def json_load():
try:
with open(DB_JSON_PATH, "r") as f:
read_data = json.load(f)
except:
read_data = []
return read_data
def json_dump(data):
with open(DB_JSON_PATH, "w") as f:
json.dump(data, f, indent=2)
def get_args():
parser = argparse.ArgumentParser(prog="todo_cli", description="todo list (cli)")
parser.add_argument("command", help="コマンドを指定する", choices=["add", "show", "delete"])
parser.add_argument("--item", type=str, help="追加/削除する文字を指定する")
return parser.parse_args()
def main():
args = get_args()
command = args.command
item = args.item
todo_items = json_load()
if command == "add":
new_todo_items = add_item(todo_items, item)
json_dump(new_todo_items)
return
if command == "show":
show_list(todo_items)
return
if command == "delete":
new_todo_items = delete_item(todo_items, item)
json_dump(new_todo_items)
return
if __name__ == "__main__":
main()
実行例
$python 02_todo_cli.py add --item a
$python 02_todo_cli.py add --item a
$python 02_todo_cli.py show
{'item': 'a', 'created_at': '2025-12-02 20:10:28.322416'}
{'item': 'a', 'created_at': '2025-12-02 20:10:34.221146'}
$python 02_todo_cli.py delete --item a
$python 02_todo_cli.py show
{'item': 'a', 'created_at': '2025-12-02 20:10:34.221146'}
やったこと
- argparseでの引数取得
-
--itemはshow実行時は不要なので必須ではないようにした - 各レコードは
item,created_atをもつ - json.load()はファイルがなかったり中身がなかったらエラーになるので一応エラーハンドリングしている
- jsonでの1レコードの変更はまぁ今回はええか…の気持ちで全レコードを上書きで書き出すようになっている
-
deleteも1行ずつ舐めて確認しているがもっと良い方法あるかも? - コマンド名をstrで比較しているが多分良くない
感想
- json普段あまり使っていないがちょっと中身を編集したりするのが意外と面倒らしい
- 面白いところの「自分の日常でそのまま使える」というのはそんなことはない
- 本当はadd, show, deleteとかはそういうクラスを準備した方がよいのかもしれない
ちょっと勉強になった。