命令行待办工具
用 Python 写一个 CLI 待办工具:argparse 解析参数、JSON 文件持久化任务列表。从浏览器跳到终端,理解程序边界与脚本思维。
离开浏览器,去终端里写一个真能用的小工具
前面七个案例都在浏览器里跑,这个项目第一次让代码离开浏览器、住进终端。写完之后你在终端敲 todo add 学完这个案例、todo list、todo done 1,就能像 git 一样管理自己今天要做的事。它教给你的不是 Python 语法,而是「程序如何接收输入、如何持久化、如何与操作系统协作」这套底层心智。
分五步做一个能当命令用的待办
从「一个 .py 文件」走到「在终端直接 todo add」的全过程。
规划命令与子命令
先想清楚要支持哪些命令:todo add <内容>、todo list、todo done <id>、todo delete <id>、todo clear。这是 argparse 里 subparsers 的典型用法——每个子命令一套参数。先在纸上列出来再动手,比写一半发现要改接口快十倍。
JSON 文件做持久化
选一个固定的存储位置,比如 ~/.todo.json。用 pathlib.Path.home() 拿到家目录,避免硬编码。读写函数各写一个:load_todos() 文件不存在就返回空列表;save_todos(todos) 用 json.dump 写入。所有子命令都围绕这两个函数,绝不让业务逻辑直接碰文件。
用 argparse 搭骨架
创建 ArgumentParser,加 subparsers = parser.add_subparsers(dest='command'),再为每个子命令 add_parser('add') 加上自己的参数。这样 python todo.py add "学完这个案例" 时,args.command 是 'add',args.content 是用户输入的字符串。argparse 帮你做了所有参数校验与帮助文档生成。
实现五个子命令
用 if/elif 按 args.command 分发:add 时 push 一条 {id, content, done: False, created_at};list 时遍历打印,未完成的用一种颜色、已完成的划线;done 把对应 id 的 done 改 True;delete 过滤掉那个 id;clear 只清已完成的,别全删。
变成系统命令
文件第一行加 #!/usr/bin/env python3,给文件加可执行权限 chmod +x todo.py,再 ln -s ~/code/todo.py /usr/local/bin/todo 建个软链。之后在任何目录敲 todo list 都能直接用,跟 git、ls 没区别。这一步让你第一次有「我写的工具进操作系统了」的实感。
关键代码片段
argparse 骨架 + 五个子命令分发,一个文件搞定一个能用的小工具。
#!/usr/bin/env python3 import argparse, json from pathlib import Path from datetime import datetime DB = Path.home() / '.todo.json' def load(): return json.loads(DB.read_text()) if DB.exists() else [] def save(todos): DB.write_text(json.dumps(todos, ensure_ascii=False, indent=2)) def main(): parser = argparse.ArgumentParser(prog='todo', description='命令行待办小工具') sub = parser.add_subparsers(dest='command', required=True) p_add = sub.add_parser('add', help='新增一条待办') p_add.add_argument('content', help='待办内容') sub.add_parser('list', help='列出所有待办') p_done = sub.add_parser('done', help='标记某条为完成') p_done.add_argument('id', type=int) args = parser.parse_args() todos = load() if args.command == 'add': todos.append({ 'id': len(todos) + 1, 'content': args.content, 'done': False, 'created_at': datetime.now().isoformat() }) save(todos) print(f'已添加:{args.content}') elif args.command == 'list': if not todos: print('暂无待办,先 add 一条吧'); return for t in todos: mark = '[x]' if t['done'] else '[ ]' print(f"{t['id']}. {mark} {t['content']}") elif args.command == 'done': for t in todos: if t['id'] == args.id: t['done'] = True save(todos) print(f'已完成 #{args.id}') if __name__ == '__main__': main()
从浏览器跳到终端,第一次让我意识到「程序」和「网页」不是一回事。网页是给所有人看的、跑在别人电脑上的程序;CLI 是给自己用的、跑在自己电脑上的程序。一个不用考虑响应式、跨浏览器、加载态的小工具,能把所有注意力都放在「逻辑对不对」上。这种纯粹感是后面写任何复杂系统的良好起点。
8 个案例全部走完
从浏览器到终端、从静态布局到状态机、从正则到本地存储,这一套练下来,你已经能独立做出一个完整的小项目了。下一步建议挑一个最喜欢的案例继续打磨,或者去小型实战项目继续刷题。