2.3.1 项目:命令行任务管理器

这是 Python 基础阶段的第一个完整小项目。你会把数据结构、函数、文件读写和异常处理组合起来,做出一个真正能保存任务、查看任务、修改任务状态的命令行工具。
- 综合运用 Python 基础知识(数据结构、函数、文件操作、异常处理)
- 体验完整的项目开发流程:需求分析 → 设计 → 编码 → 测试
- 构建一个真正可用的命令行工具
我们要构建一个命令行任务管理器(类似简易版的 Todoist),支持:
- 添加任务
- 查看所有任务
- 标记任务完成
- 删除任务
- 数据持久化(关闭程序后数据不丢失)
最终效果:
| 区域 | CLI 展示什么 |
|---|---|
| 菜单 | 查看、添加、完成、删除或退出 |
| 用户操作 | 选择 1 查看所有任务 |
| 任务列表 | 三个任务,其中一个已完成 |
| 摘要 | 共 3 个任务,已完成 1 个 |
第一步:项目规划
Section titled “第一步:项目规划”每个任务需要哪些信息?
task = { "id": 1, "title": "学习 Python 基础", "done": False, "created_at": "2026-02-09 14:30:00"}所有任务存在一个列表中,并保存到 JSON 文件。
| 模块 | 功能 |
|---|---|
| 数据管理 | 加载/保存任务到文件 |
| 任务操作 | 增删改查 |
| 用户界面 | 菜单显示、输入处理 |
第二步:基础版本
Section titled “第二步:基础版本”先实现一个最简单的版本,不带文件保存:
# todo.py —— 命令行任务管理器
from datetime import datetime
def show_menu(): """显示菜单""" print("\n===== 任务管理器 =====") print("1. 查看所有任务") print("2. 添加任务") print("3. 完成任务") print("4. 删除任务") print("5. 退出") print()
def show_tasks(tasks: list[dict]) -> None: """显示所有任务""" if not tasks: print("📭 暂无任务,快去添加一个吧!") return
print("\n📋 任务列表:") for i, task in enumerate(tasks, 1): status = "✓" if task["done"] else " " print(f' {i}. [{status}] {task["title"]} ' f'(创建于: {task["created_at"][:10]})')
done_count = sum(1 for t in tasks if t["done"]) print(f"\n共 {len(tasks)} 个任务,已完成 {done_count} 个")
def add_task(tasks: list[dict]) -> None: """添加新任务""" title = input("请输入任务标题: ").strip() if not title: print("❌ 任务标题不能为空!") return
task = { "id": len(tasks) + 1, "title": title, "done": False, "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } tasks.append(task) print(f"✅ 任务「{title}」已添加!")
def complete_task(tasks: list[dict]) -> None: """标记任务为完成""" show_tasks(tasks) if not tasks: return
try: num = int(input("请输入要完成的任务编号: ")) if 1 <= num <= len(tasks): task = tasks[num - 1] if task["done"]: print(f"⚠️ 任务「{task['title']}」已经完成过了") else: task["done"] = True print(f"✅ 任务「{task['title']}」已标记为完成!") else: print("❌ 无效的任务编号!") except ValueError: print("❌ 请输入数字!")
def delete_task(tasks: list[dict]) -> None: """删除任务""" show_tasks(tasks) if not tasks: return
try: num = int(input("请输入要删除的任务编号: ")) if 1 <= num <= len(tasks): removed = tasks.pop(num - 1) print(f"🗑️ 任务「{removed['title']}」已删除!") else: print("❌ 无效的任务编号!") except ValueError: print("❌ 请输入数字!")
def main(): """主函数""" tasks = []
print("欢迎使用任务管理器!")
while True: show_menu() choice = input("请选择操作 (1-5): ").strip()
if choice == "1": show_tasks(tasks) elif choice == "2": add_task(tasks) elif choice == "3": complete_task(tasks) elif choice == "4": delete_task(tasks) elif choice == "5": print("👋 再见!") break else: print("❌ 无效的选择,请输入 1-5")
if __name__ == "__main__": main()试一试: 把上面的代码保存为 todo.py,运行 python todo.py。
第三步:添加文件持久化
Section titled “第三步:添加文件持久化”现在程序一关数据就没了。让我们加上文件保存功能:
import jsonfrom pathlib import Path
DATA_FILE = Path("tasks.json")
def load_tasks() -> list[dict]: """从文件加载任务""" if DATA_FILE.exists(): try: with open(DATA_FILE, "r", encoding="utf-8") as f: tasks = json.load(f) print(f"📂 已加载 {len(tasks)} 个任务") return tasks except (json.JSONDecodeError, IOError) as e: print(f"⚠️ 加载数据失败: {e},将使用空列表") return []
def save_tasks(tasks: list[dict]) -> None: """保存任务到文件""" try: with open(DATA_FILE, "w", encoding="utf-8") as f: json.dump(tasks, f, ensure_ascii=False, indent=2) except IOError as e: print(f"⚠️ 保存数据失败: {e}")然后修改 main() 函数:
def main(): tasks = load_tasks() # 启动时加载
print("欢迎使用任务管理器!")
while True: show_menu() choice = input("请选择操作 (1-5): ").strip()
if choice == "1": show_tasks(tasks) elif choice == "2": add_task(tasks) save_tasks(tasks) # 添加后保存 elif choice == "3": complete_task(tasks) save_tasks(tasks) # 修改后保存 elif choice == "4": delete_task(tasks) save_tasks(tasks) # 删除后保存 elif choice == "5": save_tasks(tasks) # 退出前保存 print("👋 再见!") break else: print("❌ 无效的选择,请输入 1-5")第四步:扩展挑战
Section titled “第四步:扩展挑战”基础版完成后,试着添加以下功能来提升自己:
挑战 1:任务优先级
Section titled “挑战 1:任务优先级”给任务添加优先级(高/中/低),并支持按优先级排序显示。
挑战 2:搜索功能
Section titled “挑战 2:搜索功能”支持按关键词搜索任务标题。
挑战 3:统计功能
Section titled “挑战 3:统计功能”显示统计信息:总任务数、完成率、今日新增等。
挑战 4:用类重构
Section titled “挑战 4:用类重构”把整个项目用面向对象的方式重构:
class Task: """单个任务""" def __init__(self, title: str, priority: str = "中"): self.title = title self.priority = priority self.done = False self.created_at = datetime.now()
class TaskManager: """任务管理器""" def __init__(self, filename: str = "tasks.json"): self.filename = filename self.tasks: list[Task] = [] self.load()
def add(self, title: str, priority: str = "中") -> None: self.tasks.append(Task(title, priority))
def complete(self, index: int) -> None: self.tasks[index].done = True
def delete(self, index: int) -> None: self.tasks.pop(index)
def search(self, keyword: str) -> list[Task]: return [task for task in self.tasks if keyword.lower() in task.title.lower()]
def save(self) -> None: import json from pathlib import Path
Path(self.filename).write_text( json.dumps([task.__dict__ for task in self.tasks], ensure_ascii=False, indent=2), encoding="utf-8", )
def load(self) -> None: import json from pathlib import Path
path = Path(self.filename) if not path.exists(): return data = json.loads(path.read_text(encoding="utf-8")) self.tasks = [] for item in data: task = Task(item["title"], item.get("priority", "中")) task.done = item.get("done", False) self.tasks.append(task)项目交付参考与讲解
- 增加
priority字段,例如high、medium、low,然后在展示前按优先级排序。如果优先级相同,就让较早的created_at排在前面。 - 增加一个
search(keyword)辅助函数,对标题、状态文本和优先级做不区分大小写的匹配。 - 输出总任务数、已完成任务数、待办任务数,以及各优先级的数量。这样每次改完都能快速检查输出是否正确。
- 重构成
Task模型 +TaskManager类。让类负责load、save、add、complete、delete和search,CLI 只负责输入和打印。 - 自查时,重启程序,确认已保存的任务仍然存在,搜索能返回正确子集,完成或删除任务后,界面和
tasks.json都同步更新。
项目自查清单
Section titled “项目自查清单”完成项目后,对照检查:
- 程序能正常运行,不会因为非法输入而崩溃
- 数据保存到文件,重启后数据还在
- 代码有函数分层,不是一大坨
- 有适当的错误处理(try/except)
- 函数有文档字符串
- 变量命名清晰(符合 PEP 8)
- 用 Git 管理了项目代码
版本路线建议
Section titled “版本路线建议”| 版本 | 目标 | 交付重点 |
|---|---|---|
| 基础版 | 跑通最小闭环 | 能输入、能处理、能输出,并保留一组示例 |
| 标准版 | 形成可展示项目 | 增加配置、日志、错误处理、README 和截图 |
| 挑战版 | 接近作品集质量 | 增加评估、对比实验、失败样本分析和下一步路线 |
建议先完成基础版,不要一开始就追求大而全。每提升一个版本,都要把“新增了什么能力、怎么验证、还有什么问题”写进 README。
学完这一页,至少保留这张证据卡:
- 项目目标
- CLI、爬虫、API、AI API 调用,或集成式 Python 工作坊目标
- 运行命令
- 启动项目时使用的准确命令
- 工件
- 输出文件、API 响应、JSON 记录、截图或 README 说明
- 失败检查
- 依赖、网络、解析、路由、输入验证或 API key 问题
- 期望产出
- 可复现的迷你项目文件夹,包含运行结果和一个失败案例