news 2026/7/1 14:03:06

Python:第14天:小实战 —— 待办事项清单(命令行版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python:第14天:小实战 —— 待办事项清单(命令行版)

🎯 今日目标

  • 完成一个完整的、可运行的待办事项清单程序

  • 实现任务的增、删、改、查、标记完成

  • 数据持久化保存(重启程序数据不丢失)

  • 学会项目功能拆解和模块化设计

  • 体验“给自己写工具”的成就感


📋 一、项目需求分析

我们来设计一个命令行版待办事项清单,包含以下功能:

功能说明
查看所有任务显示所有待办事项,带编号和完成状态
添加任务在清单末尾添加一个新的待办事项
删除任务按编号删除指定的任务
标记完成按编号将任务标记为已完成
取消完成按编号将已完成的任务改回未完成(反悔功能)
清空所有删除所有任务(有二次确认)
统计信息显示总任务数、已完成数、未完成数
数据持久化任务保存在todos.txt文件中,重启程序自动加载

💡 这个工具虽然简单,但非常实用。很多人就是靠写这样的工具,学会了编程。


🧱 二、数据结构设计

2.1 数据存储格式

我们用一个列表来存储所有任务,每个任务是一个字典

python

todos = [ {"id": 1, "text": "学习Python", "done": False}, {"id": 2, "text": "写一篇博客", "done": False}, {"id": 3, "text": "完成第14天练习", "done": True}, ]

2.2 文件存储格式

保存到文件时,我们用简单的文本格式,每行一个任务:

text

1|学习Python|False 2|写一篇博客|False 3|完成第14天练习|True

|分隔不同字段,方便读取和解析。

💡 这种简单的文本格式比JSON更直观,新手也更容易理解。


📝 三、代码结构设计

text

todo.py ├── load_todos() # 从文件加载任务 ├── save_todos() # 保存任务到文件 ├── generate_id() # 生成新任务ID ├── show_todos() # 显示所有任务 ├── add_todo() # 添加任务 ├── delete_todo() # 删除任务 ├── complete_todo() # 标记完成 ├── uncomplete_todo() # 取消完成 ├── clear_all() # 清空所有 ├── show_stats() # 显示统计信息 ├── print_menu() # 打印菜单 └── main() # 主程序

📝 四、逐步编写代码

4.1 导入模块和定义常量

python

import os TODO_FILE = "todos.txt"

4.2 加载任务(从文件读取)

python

def load_todos(): """ 从文件加载任务列表 返回: list: 任务列表,每个任务是一个字典 """ todos = [] if not os.path.exists(TODO_FILE): return todos try: with open(TODO_FILE, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue parts = line.split("|") if len(parts) == 3: todo = { "id": int(parts[0]), "text": parts[1], "done": parts[2] == "True" } todos.append(todo) except Exception as e: print(f"⚠️ 加载数据时出错: {e}") return todos

4.3 保存任务(写入文件)

python

def save_todos(todos): """ 保存任务列表到文件 参数: todos: 任务列表 """ try: with open(TODO_FILE, "w", encoding="utf-8") as f: for todo in todos: f.write(f"{todo['id']}|{todo['text']}|{todo['done']}\n") return True except Exception as e: print(f"❌ 保存数据时出错: {e}") return False

4.4 生成新ID

python

def generate_id(todos): """ 生成新的任务ID(当前最大ID + 1) 参数: todos: 任务列表 返回: int: 新ID """ if not todos: return 1 return max(todo["id"] for todo in todos) + 1

4.5 显示所有任务

python

def show_todos(todos): """ 显示所有任务 参数: todos: 任务列表 """ if not todos: print("\n📭 暂无待办事项,添加一些吧!") return print("\n" + "=" * 50) print(" 📋 待办清单") print("=" * 50) # 按状态分组显示 undone = [t for t in todos if not t["done"]] done = [t for t in todos if t["done"]] # 显示未完成的 if undone: print("\n⏳ 待完成:") for todo in undone: print(f" [{todo['id']:2d}] {todo['text']}") # 显示已完成的 if done: print("\n✅ 已完成:") for todo in done: print(f" [{todo['id']:2d}] {todo['text']} {chr(10003)}") # ✓ 符号 print("\n" + "-" * 50) print(f"总计: {len(todos)} 项 | 待完成: {len(undone)} 项 | 已完成: {len(done)} 项") print("=" * 50)

4.6 添加任务

python

def add_todo(todos): """ 添加新任务 参数: todos: 任务列表 返回: bool: 是否成功 """ text = input("\n请输入新的待办事项: ").strip() if not text: print("❌ 任务内容不能为空") return False todo = { "id": generate_id(todos), "text": text, "done": False } todos.append(todo) save_todos(todos) print(f"✅ 已添加: {text}") return True

4.7 删除任务

python

def delete_todo(todos): """ 删除指定编号的任务 参数: todos: 任务列表 """ if not todos: print("\n📭 没有任务可删除") return show_todos(todos) try: todo_id = int(input("\n请输入要删除的任务编号: ")) # 查找任务 for i, todo in enumerate(todos): if todo["id"] == todo_id: confirm = input(f"确认删除 '{todo['text']}'?(y/n): ").lower() if confirm == 'y' or confirm == 'yes': removed = todos.pop(i) save_todos(todos) print(f"✅ 已删除: {removed['text']}") else: print("已取消删除") return print(f"❌ 未找到编号为 {todo_id} 的任务") except ValueError: print("❌ 请输入有效的数字编号")

4.8 标记完成

python

def complete_todo(todos): """ 标记任务为已完成 参数: todos: 任务列表 """ undone = [t for t in todos if not t["done"]] if not undone: print("\n🎉 所有任务都已完成!") return show_todos(todos) try: todo_id = int(input("\n请输入要标记完成的任务编号: ")) for todo in todos: if todo["id"] == todo_id: if todo["done"]: print(f"⚠️ '{todo['text']}' 已经完成了") return todo["done"] = True save_todos(todos) print(f"✅ 已标记完成: {todo['text']}") return print(f"❌ 未找到编号为 {todo_id} 的任务") except ValueError: print("❌ 请输入有效的数字编号")

4.9 取消完成(反悔功能)

python

def uncomplete_todo(todos): """ 将已完成的任务改回未完成 参数: todos: 任务列表 """ done = [t for t in todos if t["done"]] if not done: print("\n📝 没有已完成的任务") return show_todos(todos) try: todo_id = int(input("\n请输入要取消完成的任务编号: ")) for todo in todos: if todo["id"] == todo_id: if not todo["done"]: print(f"⚠️ '{todo['text']}' 本来就是未完成状态") return todo["done"] = False save_todos(todos) print(f"✅ 已取消完成: {todo['text']}") return print(f"❌ 未找到编号为 {todo_id} 的任务") except ValueError: print("❌ 请输入有效的数字编号")

4.10 清空所有任务

python

def clear_all(todos): """ 清空所有任务(二次确认) 参数: todos: 任务列表 """ if not todos: print("\n📭 已经是空清单了") return show_todos(todos) confirm = input("\n⚠️ 确认删除所有任务?(y/n): ").lower() if confirm == 'y' or confirm == 'yes': todos.clear() save_todos(todos) print("🗑️ 已清空所有任务") else: print("已取消操作")

4.11 显示统计信息

python

def show_stats(todos): """ 显示统计信息 参数: todos: 任务列表 """ if not todos: print("\n📭 暂无任务") return total = len(todos) done_count = sum(1 for t in todos if t["done"]) undone_count = total - done_count completion_rate = (done_count / total * 100) if total > 0 else 0 print("\n" + "=" * 40) print(" 📊 统计信息") print("=" * 40) print(f"总任务数: {total}") print(f"已完成: {done_count} 项") print(f"待完成: {undone_count} 项") print(f"完成率: {completion_rate:.1f}%") # 显示进度条 bar_length = 20 filled = int(bar_length * completion_rate / 100) bar = "█" * filled + "░" * (bar_length - filled) print(f"进度条: [{bar}]") print("=" * 40)

4.12 打印菜单

python

def print_menu(): """打印主菜单""" print("\n" + "=" * 40) print(" 📝 待办事项清单") print("=" * 40) print("1. 查看所有任务") print("2. 添加新任务") print("3. 删除任务") print("4. 标记完成") print("5. 取消完成(反悔)") print("6. 清空所有任务") print("7. 统计信息") print("8. 退出") print("=" * 40)

4.13 主程序

python

def main(): """主程序""" # 加载任务 todos = load_todos() print("=" * 40) print(" 📝 待办事项清单") print("=" * 40) print(f"已加载 {len(todos)} 项任务") # 主循环 while True: print_menu() choice = input("请选择操作(1-8): ") if choice == "1": show_todos(todos) elif choice == "2": add_todo(todos) elif choice == "3": delete_todo(todos) elif choice == "4": complete_todo(todos) elif choice == "5": uncomplete_todo(todos) elif choice == "6": clear_all(todos) elif choice == "7": show_stats(todos) elif choice == "8": # 保存数据 save_todos(todos) print("\n👋 再见!数据已保存。") break else: print("❌ 无效选择,请输入 1-8") if __name__ == "__main__": main()

📋 五、完整代码

以下是完整的todo.py文件:

python

""" 第14天实战项目:待办事项清单(命令行版) 综合运用:列表、字典、函数、文件操作、异常处理、模块化设计 """ import os TODO_FILE = "todos.txt" def load_todos(): """ 从文件加载任务列表 返回: list: 任务列表,每个任务是一个字典 """ todos = [] if not os.path.exists(TODO_FILE): return todos try: with open(TODO_FILE, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue parts = line.split("|") if len(parts) == 3: todo = { "id": int(parts[0]), "text": parts[1], "done": parts[2] == "True" } todos.append(todo) except Exception as e: print(f"⚠️ 加载数据时出错: {e}") return todos def save_todos(todos): """ 保存任务列表到文件 参数: todos: 任务列表 """ try: with open(TODO_FILE, "w", encoding="utf-8") as f: for todo in todos: f.write(f"{todo['id']}|{todo['text']}|{todo['done']}\n") return True except Exception as e: print(f"❌ 保存数据时出错: {e}") return False def generate_id(todos): """ 生成新的任务ID(当前最大ID + 1) 参数: todos: 任务列表 返回: int: 新ID """ if not todos: return 1 return max(todo["id"] for todo in todos) + 1 def show_todos(todos): """ 显示所有任务 参数: todos: 任务列表 """ if not todos: print("\n📭 暂无待办事项,添加一些吧!") return print("\n" + "=" * 50) print(" 📋 待办清单") print("=" * 50) undone = [t for t in todos if not t["done"]] done = [t for t in todos if t["done"]] if undone: print("\n⏳ 待完成:") for todo in undone: print(f" [{todo['id']:2d}] {todo['text']}") if done: print("\n✅ 已完成:") for todo in done: print(f" [{todo['id']:2d}] {todo['text']} ✓") print("\n" + "-" * 50) print(f"总计: {len(todos)} 项 | 待完成: {len(undone)} 项 | 已完成: {len(done)} 项") print("=" * 50) def add_todo(todos): """ 添加新任务 参数: todos: 任务列表 返回: bool: 是否成功 """ text = input("\n请输入新的待办事项: ").strip() if not text: print("❌ 任务内容不能为空") return False todo = { "id": generate_id(todos), "text": text, "done": False } todos.append(todo) save_todos(todos) print(f"✅ 已添加: {text}") return True def delete_todo(todos): """ 删除指定编号的任务 参数: todos: 任务列表 """ if not todos: print("\n📭 没有任务可删除") return show_todos(todos) try: todo_id = int(input("\n请输入要删除的任务编号: ")) for i, todo in enumerate(todos): if todo["id"] == todo_id: confirm = input(f"确认删除 '{todo['text']}'?(y/n): ").lower() if confirm == 'y' or confirm == 'yes': removed = todos.pop(i) save_todos(todos) print(f"✅ 已删除: {removed['text']}") else: print("已取消删除") return print(f"❌ 未找到编号为 {todo_id} 的任务") except ValueError: print("❌ 请输入有效的数字编号") def complete_todo(todos): """ 标记任务为已完成 参数: todos: 任务列表 """ undone = [t for t in todos if not t["done"]] if not undone: print("\n🎉 所有任务都已完成!") return show_todos(todos) try: todo_id = int(input("\n请输入要标记完成的任务编号: ")) for todo in todos: if todo["id"] == todo_id: if todo["done"]: print(f"⚠️ '{todo['text']}' 已经完成了") return todo["done"] = True save_todos(todos) print(f"✅ 已标记完成: {todo['text']}") return print(f"❌ 未找到编号为 {todo_id} 的任务") except ValueError: print("❌ 请输入有效的数字编号") def uncomplete_todo(todos): """ 将已完成的任务改回未完成 参数: todos: 任务列表 """ done = [t for t in todos if t["done"]] if not done: print("\n📝 没有已完成的任务") return show_todos(todos) try: todo_id = int(input("\n请输入要取消完成的任务编号: ")) for todo in todos: if todo["id"] == todo_id: if not todo["done"]: print(f"⚠️ '{todo['text']}' 本来就是未完成状态") return todo["done"] = False save_todos(todos) print(f"✅ 已取消完成: {todo['text']}") return print(f"❌ 未找到编号为 {todo_id} 的任务") except ValueError: print("❌ 请输入有效的数字编号") def clear_all(todos): """ 清空所有任务(二次确认) 参数: todos: 任务列表 """ if not todos: print("\n📭 已经是空清单了") return show_todos(todos) confirm = input("\n⚠️ 确认删除所有任务?(y/n): ").lower() if confirm == 'y' or confirm == 'yes': todos.clear() save_todos(todos) print("🗑️ 已清空所有任务") else: print("已取消操作") def show_stats(todos): """ 显示统计信息 参数: todos: 任务列表 """ if not todos: print("\n📭 暂无任务") return total = len(todos) done_count = sum(1 for t in todos if t["done"]) undone_count = total - done_count completion_rate = (done_count / total * 100) if total > 0 else 0 print("\n" + "=" * 40) print(" 📊 统计信息") print("=" * 40) print(f"总任务数: {total}") print(f"已完成: {done_count} 项") print(f"待完成: {undone_count} 项") print(f"完成率: {completion_rate:.1f}%") bar_length = 20 filled = int(bar_length * completion_rate / 100) bar = "█" * filled + "░" * (bar_length - filled) print(f"进度条: [{bar}]") print("=" * 40) def print_menu(): """打印主菜单""" print("\n" + "=" * 40) print(" 📝 待办事项清单") print("=" * 40) print("1. 查看所有任务") print("2. 添加新任务") print("3. 删除任务") print("4. 标记完成") print("5. 取消完成(反悔)") print("6. 清空所有任务") print("7. 统计信息") print("8. 退出") print("=" * 40) def main(): """主程序""" todos = load_todos() print("=" * 40) print(" 📝 待办事项清单") print("=" * 40) print(f"已加载 {len(todos)} 项任务") while True: print_menu() choice = input("请选择操作(1-8): ") if choice == "1": show_todos(todos) elif choice == "2": add_todo(todos) elif choice == "3": delete_todo(todos) elif choice == "4": complete_todo(todos) elif choice == "5": uncomplete_todo(todos) elif choice == "6": clear_all(todos) elif choice == "7": show_stats(todos) elif choice == "8": save_todos(todos) print("\n👋 再见!数据已保存。") break else: print("❌ 无效选择,请输入 1-8") if __name__ == "__main__": main()

📸 六、运行结果演示

启动程序:

text

======================================== 📝 待办事项清单 ======================================== 已加载 3 项任务 ======================================== 📝 待办事项清单 ======================================== 1. 查看所有任务 2. 添加新任务 3. 删除任务 4. 标记完成 5. 取消完成(反悔) 6. 清空所有任务 7. 统计信息 8. 退出 ======================================== 请选择操作(1-8): 1 ================================================== 📋 待办清单 ================================================== ⏳ 待完成: [ 1] 学习Python [ 2] 写一篇博客 ✅ 已完成: [ 3] 完成第14天练习 ✓ -------------------------------------------------- 总计: 3 项 | 待完成: 2 项 | 已完成: 1 项 ==================================================

添加任务:

text

请选择操作(1-8): 2 请输入新的待办事项: 去超市买菜 ✅ 已添加: 去超市买菜

标记完成:

text

请选择操作(1-8): 4 ================================================== 📋 待办清单 ================================================== ⏳ 待完成: [ 1] 学习Python [ 2] 写一篇博客 [ 4] 去超市买菜 ✅ 已完成: [ 3] 完成第14天练习 ✓ -------------------------------------------------- 总计: 4 项 | 待完成: 3 项 | 已完成: 1 项 ================================================== 请输入要标记完成的任务编号: 4 ✅ 已标记完成: 去超市买菜

统计信息:

text

请选择操作(1-8): 7 ======================================== 📊 统计信息 ======================================== 总任务数: 4 已完成: 2 项 待完成: 2 项 完成率: 50.0% 进度条: [██████████░░░░░░░░░░] ========================================

🎯 今日总结

今天你通过待办事项清单项目,综合运用了:

知识点用在什么地方
列表存储所有任务
字典每个任务的“ID、内容、状态”
函数每个功能独立封装
文件操作读取和保存todos.txt
异常处理输入校验、文件读写错误
循环主菜单循环
条件判断菜单路由、状态判断
列表推导式筛选已完成/未完成的任务
模块化设计一个函数做一件事
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/27 22:48:21

网络隔离下的数据孤岛:内外网数据交换平台如何打通任督二脉?

网络隔离与数据共享,真的水火不容吗?事实并非如此。真正的问题不在于隔离本身,而在于缺乏一套安全高效的内外网数据交换平台来打通这“任督二脉”。当数据被锁死在各自的“孤岛”中,企业不仅面临效率低下的困扰,更可能…

作者头像 李华
网站建设 2026/6/27 22:42:53

开源热榜 | 2026-06-26:Agent化浪潮从工具席卷到旅行、投资与安全

昨日对比速览状态项目昨排今排变化持续google-labs-code/design.md101暴升9位,Star增138%持续calesthio/OpenMontage12小幅回落,仍领跑视频赛道新进xbtlin/ai-berkshire-3首次上榜新进mauriceboe/TREK-4首次上榜持续apple/container35下降2位持续JCodesM…

作者头像 李华
网站建设 2026/6/27 22:31:15

算力登顶的制造隐喻:超算“灵晟”背后的中国工业信号

一、算力:制造业的第五大通用生产要素“灵晟”再度登顶全球超算榜单,释放的首要信号是:算力正从尖端科研工具,蜕变为制造业不可或缺的基础设施。过去,制造业的要素禀赋是土地、电力、人力和资本。在智能化转型的深水区…

作者头像 李华
网站建设 2026/6/27 22:28:18

AI编程多Agent架构三足鼎立:Claude Code的P2P协同、Codex的云原生并行与Gemini的计划驱动——一个研发老兵的技术选型框架

2026年2月的一周内,Claude Code、OpenAI Codex、Cursor、Grok Build、Windsurf几乎同时发布了多Agent支持。这不是巧合,而是架构必然。本文从研发视角出发,深入剖析三种多Agent架构范式的设计差异、技术权衡与选型策略。一、单Agent为何触顶&…

作者头像 李华