简介:这是一份面向 Python 初学者的命令行待办事项练习资源,帮助读者在本地环境中通过实现增删任务、保存与加载数据等核心功能,掌握函数封装、文件读写与 CLI 交互的基本思路。压缩包共 7 个文件,约 295KB,包含 2 个 py 脚本分别承载应用主逻辑与测试用例,1 个 json 与 1 个 csv 用于任务数据的持久化存储,另有 md 说明文档、gitignore 配置及 gif 演示动图,结构精简、开箱即用。资源围绕 add_one_task、print_list、delete_task、save_todos、load_todos 五个待实现函数展开,读者可先运行测试脚本验证进度,再启动主程序体验完整流程,逐步理解命令行参数解析、列表增删与文件序列化的配合方式。目前已有 355 人学习,适合作为 Python 基础语法与小型项目实战的衔接练习,也可用于课堂作业或自学打卡。
1. 从一团乱麻到一条命令:这个待办工具到底能帮你做什么
你有没有过这种时刻:脑子里同时压着七八件事,写下来怕丢,不写又一直惦记,手机备忘录翻半天找不到重点,最后干脆靠脑子硬扛,结果漏了一件被追问时才想起来。更麻烦的是,很多在线待办工具要注册、要联网、要同步,你只是想安安静静记个事,却先被引导着走完一套流程。这份 Exercise-todo-list-cli-python 就是冲着这种场景来的:它是一个用 Python 写的、只在本地跑的待办事项列表命令行工具,不联网、不注册、不弹窗,打开终端敲一行命令就能记、能看、能勾掉。它适合刚学 Python、想找一个能真正跑起来的小项目练手的人,也适合只想把待办管明白、不想被工具绑架的人。你不需要先懂什么高深概念,只要电脑上有 Python,就能跟着往下走。
2. 为什么值得从它入手:先搞懂命令行待办这件事
2.1 它和手机备忘录到底差在哪
很多人第一次听到「命令行待办」会本能地皱眉:黑底白字,是不是很难用?其实你可以把它想成一个只认文字的抽屉。手机备忘录像一个大杂物箱,什么都能塞,但找起来靠翻;命令行待办更像一排贴了标签的小格子,你每次只做一件事——放进去、看一眼、划掉。它的优势不在花哨,而在快和稳:不用等 App 启动,不用登录,不用同步,敲完回车结果立刻出现。对新手来说,这种「输入什么就得到什么」的反馈特别重要,因为你能清楚看到自己写的代码到底干了什么,而不是被一层层界面挡住。它解决的核心问题就一个:把「记下来」这件事的成本降到几乎为零,让你愿意真的去记。
2.2 为什么用 Python 写待办最合适
Python 在这类小工具上有天然优势。第一,语法接近自然语言,读起来不费劲,你不需要先啃一堆符号才能看懂逻辑。第二,标准库自带处理文件和列表的能力,待办数据存本地、读本地,几行代码就能搞定,不用装额外框架。第三,命令行交互用内置的 input 和 print 就能完成,新手不会被图形界面、网络请求这些额外概念劝退。换句话说,这个项目把「学 Python」和「做一个有用的小东西」绑在了一起:你写的每一行都有明确目的,不是为练习而练习。我第一次带人入门时发现,凡是能当天跑出结果的小项目,坚持率远高于纯看语法。待办列表正好属于这一类——门槛低,但完整覆盖了变量、列表、循环、条件判断、文件读写这些核心知识点。
2.3 先看清它的边界:仅限本地意味着什么
标题里「仅限本地」四个字很关键,它不是缺点,而是定位。数据存在你自己电脑的一个文件里,不经过任何服务器,所以没有账号、没有云端、没有多人协作。好处是简单、私密、离线可用;代价是换电脑要手动拷文件,多人共享得自己想办法。对入门阶段来说,这恰恰是优点:你不需要理解网络、数据库、并发这些还没学的东西,就能把整个流程跑通。等你把这个本地版本吃透了,再去扩展成联网版,心里会有底得多。所以别一上来就想着「能不能同步到手机」,先把本地这条链路走顺,才是新手最该做的事。
3. 动手第一步:把第一个待办跑起来
3.1 动手前先确认两件事
在写任何代码之前,先确认你的电脑上装了 Python,并且能在终端里调用它。打开终端(Windows 用 PowerShell 或 CMD,macOS 和 Linux 用系统自带的终端),输入下面这行命令:
python --version如果显示类似 Python 3.x.x 的字样,说明环境没问题。如果提示找不到命令,可以试试把 python 换成 python3 再输一次。这一步看着简单,却是新手翻车最多的地方——很多人后面代码报错,其实根源是 Python 根本没装好或者没加进环境变量。确认版本在 3.6 以上就够了,这个项目用不到太新的特性。接着找一个你放代码的文件夹,比如在桌面上新建一个 todo 目录,后面所有文件都放这里,避免文件散落各处找不到。
3.2 第一个能跑的版本:只做「添加」和「查看」
先别急着写完整功能,新手最容易犯的错是一上来就想把增删改查全写完,结果卡在中间失去信心。我们分步来,第一个版本只做两件事:添加待办、查看待办。新建一个文件,命名成 todo.py,写入下面的代码:
# 用一个列表在内存里暂存待办事项 todos = [] while True: # 打印菜单,让用户知道能做什么 print("\n1. 添加待办 2. 查看待办 3. 退出") choice = input("请输入选项数字:") if choice == "1": # 读取用户输入的内容并追加到列表 item = input("要添加什么:") todos.append(item) print("已添加:", item) elif choice == "2": # 遍历列表,按序号打印出来 if not todos: print("还没有待办事项") else: for index, item in enumerate(todos, start=1): print(f"{index}. {item}") elif choice == "3": print("再见") break else: print("请输入 1、2 或 3")这段代码的逻辑很直白:todos 是一个列表,用来装待办;while True 让程序一直循环,直到你选退出;input 负责接收你的输入;append 把新事项塞进列表;enumerate 在打印时自动加上序号。运行方式是回到终端,进入文件所在目录,输入:
python todo.py然后按提示操作,添加几条、查看一下、再退出。如果你能顺利走完这一圈,恭喜,你已经跑通了最核心的交互骨架。这里的关键参数是 start=1,它让序号从 1 开始而不是默认的 0,对使用者更友好;这个细节虽小,但体现了「工具是给人用的」这个思路。
3.3 让待办活下来:把数据存进本地文件
上面那个版本有个致命问题:一退出,待办全没了,因为数据只在内存里。要让它真正有用,必须写进本地文件。我们加两个函数,一个负责读,一个负责写:
import json import os FILE_NAME = "todos.json" def load_todos(): # 文件不存在就返回空列表,避免第一次运行报错 if not os.path.exists(FILE_NAME): return [] with open(FILE_NAME, "r", encoding="utf-8") as f: return json.load(f) def save_todos(todos): # 每次改动后整体写回文件 with open(FILE_NAME, "w", encoding="utf-8") as f: json.dump(todos, f, ensure_ascii=False, indent=2)然后在程序开头把 todos = [] 换成 todos = load_todos(),在每次添加之后调用 save_todos(todos)。这里用 JSON 格式存,是因为它既能被 Python 直接读写,又能用文本编辑器打开看,出问题时方便排查。ensure_ascii=False 保证中文正常显示而不是变成一串编码,indent=2 让文件内容有缩进、便于阅读。encoding="utf-8" 则是防止中文在不同系统上乱码。做完这一步,你退出再重新运行,之前添加的待办还在,这个工具才算真正立住了。
4. 把功能补全:删除、完成与更顺手的交互
4.1 加上删除和标记完成
一个只能加不能删的待办列表,用两天就会变成垃圾场。我们给每个待办加上「是否完成」的状态,并支持删除。把原来存字符串的列表改成存字典:
# 每条待办是一个字典,包含内容和完成状态 todos.append({"text": item, "done": False})查看时根据 done 显示不同标记:
for index, todo in enumerate(todos, start=1): mark = "[x]" if todo["done"] else "[ ]" print(f"{index}. {mark} {todo['text']}")再增加两个菜单项,一个用来切换完成状态,一个用来删除:
elif choice == "4": num = int(input("要标记完成的序号:")) todos[num - 1]["done"] = True save_todos(todos) elif choice == "5": num = int(input("要删除的序号:")) todos.pop(num - 1) save_todos(todos)注意 num - 1 这个减法:用户看到的是从 1 开始的序号,而列表下标从 0 开始,不减一就会删错或越界。这是新手极容易忽略的一处,写的时候心里默念「给人看从 1 起,给程序用从 0 起」,能省下不少调试时间。
4.2 处理输入错误,别让程序一崩了之
上面那段代码有个隐患:如果用户在要求输入序号时敲了字母,int() 会直接抛异常,整个程序崩掉。真实使用中这种事几乎必然发生,所以必须加保护:
try: num = int(input("要删除的序号:")) todos.pop(num - 1) save_todos(todos) except (ValueError, IndexError): print("序号无效,请重新输入")try 负责尝试执行可能出错的代码,except 负责接住错误并给出友好提示。ValueError 对应「输入的不是数字」,IndexError 对应「序号超出范围」。把这两个都接住,程序就不会因为一次误输入而退出。这种「先想哪里会错,再决定怎么兜住」的习惯,比多写几个功能更能提升代码质量,也是从新手走向能用的分水岭。
4.3 用参数让命令更利落
每次运行都进菜单点来点去,用久了会嫌慢。可以借助 sys.argv 支持直接带参数执行,比如 python todo.py add "写周报" 就添加一条,python todo.py list 就列出全部。核心是读取命令行参数:
import sys if len(sys.argv) > 1: command = sys.argv[1] if command == "add" and len(sys.argv) > 2: todos.append({"text": sys.argv[2], "done": False}) save_todos(todos) print("已添加") elif command == "list": for index, todo in enumerate(todos, start=1): mark = "[x]" if todo["done"] else "[ ]" print(f"{index}. {mark} {todo['text']}")sys.argv 是一个列表,第 0 个是脚本名,后面依次是你敲的参数。这样你就能把常用操作压缩成一行命令,甚至写进快捷方式。对新手来说,这一步的价值不只是「更方便」,而是让你第一次体会到「程序可以被别人用不同方式调用」,这是理解接口概念的起点。
5. 新手避坑:这几个地方最容易卡住
5.1 现象:运行报错「No such file or directory」
原因:终端当前所在目录和你存放 todo.py 的目录不一致,程序找不到文件,或者读写 todos.json 时路径对不上。解决:先用 cd 命令切到文件所在目录,再运行 python todo.py;如果还是不行,用 pwd(Windows 用 cd)确认当前位置,必要时用绝对路径。养成「先看自己在哪,再运行」的习惯,能省掉大量莫名其妙的报错。
5.2 现象:中文显示成乱码
原因:文件读写时没有指定编码,系统默认编码和你的内容不匹配。解决:所有 open() 都加上 encoding="utf-8",json.dump 加上 ensure_ascii=False。这两处一加,中文基本不会再出问题。如果终端本身显示乱码,那是终端编码设置的事,和代码无关,换个支持 UTF-8 的终端即可。
5.3 现象:删除了错误的待办,或者程序提示下标越界
原因:忘了把用户看到的序号减一,或者用户输入的序号超过了列表长度。解决:统一在取值时做 num - 1,并用 try/except 接住 IndexError;更稳妥的做法是先判断 1 <= num <= len(todos) 再操作。序号转换是命令行工具里最经典的坑,几乎每个人都会踩一次。
5.4 现象:改了代码但运行结果没变
原因:要么文件没保存,要么运行的是另一个同名文件,要么 Python 缓存了旧版本。解决:先确认编辑器已保存,再确认终端里运行的路径正确,必要时关掉重开终端。这类问题不涉及逻辑,纯粹是环境问题,但特别消耗新手信心,遇到时先别怀疑自己代码写错了。
5.5 现象:数据文件被写坏,待办全丢
原因:程序在写入过程中被强制中断,JSON 文件只写了一半。解决:写入前先把内容写到临时文件,成功后再替换原文件;或者每次改动前手动备份一份 todos.json。对入门项目来说,手动备份就够用,但要有这个意识——数据一旦丢了,没有后悔药可吃。
6. 下一步往哪走:从能跑到好用
把上面这些跑通之后,你手里已经有一个能真正用的本地待办工具了。接下来别急着加花哨功能,先按下面的路径把基础打牢。第一步,把代码拆成函数:现在所有逻辑挤在一个 while 里,读起来累,改成 add_todo、list_todos、delete_todo 这样的独立函数,每个只干一件事,主循环只负责调度。这一步能让你第一次理解「模块化」到底在解决什么问题。第二步,加上截止日期和优先级:给每条待办多存两个字段,查看时按优先级排序,这会把列表、字典、排序这几个知识点串起来。第三步,学一点测试:给核心函数写几个简单断言,改代码后跑一遍,确认没把原来的功能弄坏。第四步,如果你还有兴趣,再考虑把它包装成可以用 pip 安装的命令行工具,那时候你会自然接触到项目结构和打包,而不是被硬塞概念。
| 阶段 | 目标 | 涉及知识点 |
|---|---|---|
| 拆分函数 | 代码可读、可维护 | 函数定义、参数、返回值 |
| 加字段 | 支持日期与优先级 | 字典、排序、日期处理 |
| 写测试 | 改动不破坏旧功能 | 断言、测试思路 |
| 打包 | 像正式工具一样安装 | 项目结构、入口配置 |
我自己的血泪经验是:每次加新功能前,先把当前版本完整跑一遍,确认基线是好的,再去动代码。这样一旦出问题,你能立刻知道是新改动引起的,而不是在一堆变化里大海捞针。从那以后我每次动手前都强制走一遍这个确认流程,省下的调试时间远比那几分钟多。希望这份入门路径能帮到你,先从第一个能跑的版本开始,别贪多,跑通比写完更重要。
本文还有配套的精品资源,点击获取