14.跟练这个项目,你就算真正入门 Python 了
·
跟练这个项目,你就算真正入门 Python 了
学了那么多语法,不动手写一个完整的项目,等于没学。
这篇带你从零写一个命令行 Todo 应用。变量、数据结构、函数、类、文件读写、异常处理——全用上了。
项目长什么样?
>> 我的待办事项 <<
1. [x] [高] 学习Python
2. [ ] [中] 跑步30分钟
3. [ ] [低] 写周报
命令: add / complete / delete / list / save / quit
功能:
- 添加、完成、删除待办
- 设定优先级(高/中/低)
- 数据持久化到 JSON 文件
- 启动自动加载、退出自动保存
第一步:设计数据结构
{
"title": "学习Python",
"priority": "高",
"completed": False,
"created_at": "2026-06-23 16:30"
}
用字典存单个待办,用列表存全部。优先级用一个简单的枚举。
第二步:搭建骨架
import json
from datetime import datetime
from pathlib import Path
DATA_FILE = "todos.json"
PRIORITIES = {"高": "高", "中": "中", "低": "低"}
def load_todos():
"""从文件加载待办列表"""
path = Path(DATA_FILE)
if not path.exists():
return []
try:
text = path.read_text(encoding="utf-8")
return json.loads(text)
except (json.JSONDecodeError, UnicodeDecodeError):
print("数据文件损坏,已重置")
return []
def save_todos(todos):
"""保存待办列表到文件"""
with open(DATA_FILE, "w", encoding="utf-8") as f:
json.dump(todos, f, ensure_ascii=False, indent=2)
def add_todo(todos):
"""添加待办"""
title = input("待办内容:").strip()
if not title:
print("内容不能为空")
return
priority = input("优先级(高/中/低,默认中):").strip()
if priority not in PRIORITIES:
priority = "中"
todo = {
"title": title,
"priority": priority,
"completed": False,
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
}
todos.append(todo)
print(f"已添加:{title}")
def complete_todo(todos):
"""完成待办"""
list_todos(todos)
try:
index = int(input("完成第几个?")) - 1
if 0 <= index < len(todos):
todos[index]["completed"] = True
print(f"已完成:{todos[index]['title']}")
else:
print("序号无效")
except ValueError:
print("请输入数字")
def delete_todo(todos):
"""删除待办"""
list_todos(todos)
try:
index = int(input("删除第几个?")) - 1
if 0 <= index < len(todos):
removed = todos.pop(index)
print(f"已删除:{removed['title']}")
else:
print("序号无效")
except ValueError:
print("请输入数字")
def list_todos(todos):
"""显示待办列表"""
if not todos:
print("\n 还没有待办事项\n")
return
print(f"\n {'我的待办事项':-^30}\n")
for i, todo in enumerate(todos, 1):
status = "x" if todo["completed"] else " "
print(f" {i}. [{status}] [{todo['priority']}] {todo['title']}")
print()
def show_stats(todos):
"""显示统计"""
total = len(todos)
completed = sum(1 for t in todos if t["completed"])
pending = total - completed
print(f"\n 总计 {total} 项,已完成 {completed},未完成 {pending}\n")
def show_menu():
"""显示命令菜单"""
print("命令:")
print(" add - 添加待办")
print(" list - 查看列表")
print(" done - 标记完成")
print(" delete - 删除待办")
print(" stats - 统计")
print(" clear - 清空已完成的")
print(" save - 保存到文件")
print(" quit - 保存并退出")
print()
def clear_completed(todos):
"""清除已完成的待办"""
before = len(todos)
todos[:] = [t for t in todos if not t["completed"]]
removed = before - len(todos)
print(f"已清除 {removed} 项已完成的待办")
def main():
todos = load_todos()
show_stats(todos)
while True:
show_menu()
cmd = input("> ").strip().lower()
if cmd in ("add", "a"):
add_todo(todos)
elif cmd in ("list", "l"):
list_todos(todos)
elif cmd in ("done", "d"):
complete_todo(todos)
elif cmd in ("delete", "rm"):
delete_todo(todos)
elif cmd in ("stats", "s"):
show_stats(todos)
elif cmd in ("clear", "c"):
clear_completed(todos)
elif cmd in ("save", "w"):
save_todos(todos)
print("已保存")
elif cmd in ("quit", "q", "exit"):
save_todos(todos)
print("再见!")
break
else:
print(f"未知命令:{cmd},输入 help 或 ? 查看可用命令")
show_menu()
if __name__ == "__main__":
main()
第三步:一次加上所有好用的小功能
上面是基础版,下面是增强版,加上:
- 按优先级排序
- 搜索功能
- 编辑已有待办
def sort_todos(todos):
"""按优先级排序(高→中→低),同优先级已完成排后面"""
priority_order = {"高": 0, "中": 1, "低": 2}
todos.sort(key=lambda t: (priority_order.get(t["priority"], 1), t["completed"]))
def search_todos(todos):
"""搜索待办"""
keyword = input("搜索关键字:").strip()
if not keyword:
return
results = [t for t in todos if keyword in t["title"]]
if results:
print(f"\n 找到 {len(results)} 条:")
for i, todo in enumerate(results, 1):
status = "x" if todo["completed"] else " "
print(f" {i}. [{status}] [{todo['priority']}] {todo['title']}")
else:
print("没找到匹配的待办")
def edit_todo(todos):
"""编辑待办"""
list_todos(todos)
try:
index = int(input("编辑第几个?")) - 1
if 0 <= index < len(todos):
todo = todos[index]
new_title = input(f"新内容(直接回车保留'{todo['title']}'):").strip()
if new_title:
todo["title"] = new_title
new_priority = input(f"新优先级(直接回车保留'{todo['priority']}'):").strip()
if new_priority in PRIORITIES:
todo["priority"] = new_priority
print("已更新")
else:
print("序号无效")
except ValueError:
print("请输入数字")
把这几个函数加到主菜单里,就是一个功能完整的 Todo 应用了。
用到的知识点回顾
| 知识点 | 用在哪儿 |
|---|---|
| 变量和数据类型 | todos 列表,todo 字典 |
| 字符串操作 | f-string 格式化输出 |
| 列表操作 | append、pop、列表推导式 |
| 字典操作 | todo["title"] 读写 |
| 条件判断 | if cmd == "add" 命令路由 |
| 循环 | while True 主循环 |
| 函数 | add_todo、save_todos 等 |
| 文件读写 | json.load、json.dump |
| 异常处理 | try/except ValueError |
| 路径处理 | Path 检查文件是否存在 |
一个 200 行的项目,前面学的东西全用上了。
还可以继续加的东西
如果你想把项目做得更完整:
- 给待办加截止日期(
datetime) - 按多种方式排序(日期、优先级、完成状态)
- 分类标签(工作/生活/学习)
- 用
argparse支持命令行参数 - 彩色输出(
rich库) - 导出为 Markdown
写在最后
这个 Todo 应用不是多高大上的东西,但它把一个 Python 新手应该会的所有知识点都串起来了。
建议你把代码从头敲一遍,不要复制粘贴。敲的过程中你会遇到缩进错误、变量名拼错、忘了冒号……每个错误都是一次学习。
全系列 15 篇文章到这里就结束了。从 print("Hello World") 到写出完整的命令行应用,希望这个系列帮你少走弯路。
有疑问的评论区聊。
更多推荐
所有评论(0)