10.2 实战项目二:待办清单
项目目标
做一个命令行版的 TODO 待办清单,支持:
- 查看所有待办
- 添加待办
- 完成(删除)待办
- 数据保存到文件,下次打开还在
用到的知识:列表、函数、文件读写、循环、异常处理。这是最接近"真实小工具"的项目。
程序结构设计
写代码前先想清楚结构(这一步比写代码更重要):
数据:todos = ["买牛奶", "写作业"] ← 一个列表存所有待办
文件:todo.txt ← 一行一条,永久保存
函数:
load_todos() 从文件读取待办,返回列表
save_todos(todos) 把列表写入文件
show_todos(todos) 显示所有待办
main() 主循环:显示菜单 → 接收选择 → 执行对应操作
完整代码
# todo.py — 命令行待办清单
import os
FILENAME = "todo.txt"
def load_todos():
"""从文件加载待办列表;文件不存在返回空列表"""
if not os.path.exists(FILENAME):
return []
with open(FILENAME, "r", encoding="utf-8") as f:
return [line.strip() for line in f if line.strip()]
def save_todos(todos):
"""把待办列表保存到文件"""
with open(FILENAME, "w", encoding="utf-8") as f:
for todo in todos:
f.write(todo + "\n")
def show_todos(todos):
"""显示所有待办"""
if not todos:
print("(空空如也,好好休息~)")
return
for i, todo in enumerate(todos, start=1):
print(f" {i}. {todo}")
def main():
todos = load_todos()
while True:
print("\n===== 待办清单 =====")
show_todos(todos)
print("--------------------")
print("1 添加 2 完成 3 退出")
choice = input("请选择:")
if choice == "1":
item = input("要添加的事项:").strip()
if item:
todos.append(item)
save_todos(todos)
print(f"已添加:{item}")
else:
print("不能添加空事项")
elif choice == "2":
if not todos:
print("没有待办可完成")
continue
try:
num = int(input("完成第几项:"))
done = todos.pop(num - 1) # 显示从 1 开始,索引从 0 开始
save_todos(todos)
print(f"✅ 已完成:{done}")
except (ValueError, IndexError):
print("无效的编号")
elif choice == "3":
print("再见!")
break
else:
print("请输入 1、2 或 3")
if __name__ == "__main__":
main()
值得细看的几个点
1. 列表推导式(一种简洁写法,第一次见可以先记住效果):
return [line.strip() for line in f if line.strip()]
# 等价于:
result = []
for line in f:
if line.strip(): # 跳过空行
result.append(line.strip())
return result
2. 编号换算:给用户看的编号从 1 开始,列表索引从 0 开始,所以 pop(num - 1)。这种"人类编号 vs 程序索引"的换算非常常见。
3. 一个 except 接住两种异常:except (ValueError, IndexError): 同时处理"输入不是数字"和"编号超范围"。
4. 每次改动立即存盘:append/pop 之后马上 save_todos,程序意外退出也不丢数据。
挑战任务
- 增加"清空全部"功能(菜单选项 4)。
- 完成的事项不直接删除,而是移到
done.txt存档。 - 给每条待办加上添加时间(提示:
datetime.now().strftime(...),存文件时用逗号分隔)。
你学到了什么
- 先设计再编码:数据用什么结构存、拆成哪些函数
- 加载/保存/显示各司其职,main 只负责调度——这就是模块化思维
- 用户输入永远不可信,处处要校验
下一个项目:10.3 英文词频统计