首页/新闻资讯/正文详情

【第43期】Python 命令行待办:不用数据库,把列表、文件和异常做成可恢复的 CLI

发布时间:2026/9/24 17:32:19 来源:云帆数科 栏目:资讯中心
【第43期】Python 命令行待办:不用数据库,把列表、文件和异常做成可恢复的 CLI
【第43期】Python 命令行待办不用数据库把列表、文件和异常做成可恢复的 CLICSDN 完整教程系列《从小白到 AI 大模型开发工程师的进阶之路》技术点AI-0131 命令行待办事项主人公小蓝伞前置AI-0123 文件读写AI-0130 调试与测试本期产出可持久化 CLI 工具第 42 期把测试习惯立住了。小蓝伞接下来要一个真正能每天用的小工具待办事项。他第一版把列表只放在内存里关终端就丢第二版写入todos.json从项目根运行和从脚本目录运行时却出现两份内容。问题不是 JSON 偶尔失忆而是相对路径跟随当前工作目录。本期交付一个支持add/list/done的完整 CLI路径固定、写入可恢复、坏文件明确失败并用六组输入验证数据不会在错误分支中被清空。这些习惯会直接影响下一期抓取结果如何可靠落盘。一、小蓝伞遇到的问题需求看起来简单添加、完成、列出、退出后还能看见。真正的坑是空输入、重复标题、完成一个不存在的编号JSON 写到一半断电读回来是半截文件相对路径依赖当前工作目录不是脚本所在目录建议插图 1内存列表、错误 cwd 下的 json、脚本旁 json 三种结果对照。二、先给结论能关终端再打开仍在的数据才叫持久化写到哪里必须由脚本位置决定而不是你碰巧站在哪个目录。用列表保存待办用 JSON 落盘。文件路径用Path(__file__).resolve().parent。先写临时文件再替换避免写到一半损坏。所有命令先校验输入再改数据。用第 42 期的测试方式覆盖空输入、缺文件、坏 JSON。三、本文要解决什么项目内容目标可持久化 CLI输入add/list/done/quit 文本命令输出todos.json重启后可还原成功判据正常添加完成编号越界失败且不丢数据坏 JSON 可报错不崩溃不在范围多用户、数据库、Web UI四、前置准备python--version mkdir D:\ai-learning\issue-43不要把 JSON 提交到公开仓库如果里面有私人事项。先备份已有todos.json。五、核心原理列表适合保留显示顺序任务对象用字典表示编号用稳定的整数。这里不用列表下标充当编号删除第一项后下标会整体前移用户手里的“任务 3”可能突然指向另一条。新增编号应取已有最大值加一完成动作只改done不悄悄删除数据。路径有三个概念Path.cwd()是进程从哪里启动__file__是脚本在哪里数据文件是产品约定存在哪里。写Path(todos.json)等于把产品约定交给启动方式从 IDE、任务计划和终端启动可能落到三个目录。学习项目可把数据目录作为参数传入入口再默认选择脚本旁的data。这样测试能使用临时目录生产入口也不依赖用户当前站在哪儿。直接覆盖还有第二个风险序列化完成前进程退出会留下半截 JSON。更稳妥的次序是“同目录临时文件 -flush-fsync-os.replace”。同一文件系统内替换能避免读者看见半成品但它不等于数据库事务也不能解决两个进程同时写。解析失败更不能返回空列表后保存那会把仍可人工抢救的残骸变成合法空文件。错误写法与正确写法的差别不是语法风格# 错路径随 cwd 变化坏文件被伪装成空数据try:itemsjson.loads(Path(todos.json).read_text())exceptException:items[]# 对路径由调用者给出JSON 损坏向上报告itemsload_items(data_path)六、完整项目目录结构issue-43/ ├── todo.py └── data/ # 首次保存时自动创建todo.py是可直接运行的完整版本from__future__importannotationsfromdataclassesimportasdict,dataclassfrompathlibimportPathimportargparseimportjsonimportosimporttempfile DEFAULT_DATAPath(__file__).resolve().parent/data/todos.jsondataclassclassItem:id:inttitle:strdone:boolFalsedefload(path:Path)-list[Item]:从 JSON 加载任务文件不存在表示首次使用文件损坏则失败。ifnotpath.exists():return[]rawjson.loads(path.read_text(encodingutf-8))ifnotisinstance(raw,list):raiseValueError(todos.json 结构必须是列表)items[Item(**row)forrowinraw]iflen({item.idforiteminitems})!len(items):raiseValueError(任务编号不能重复)returnitemsdefsave(path:Path,items:list[Item])-None:先完整写入同目录临时文件再原子替换目标文件。payloadjson.dumps([asdict(x)forxinitems],ensure_asciiFalse,indent2)path.parent.mkdir(parentsTrue,exist_okTrue)fd,tmptempfile.mkstemp(dirpath.parent,suffix.tmp)try:withos.fdopen(fd,w,encodingutf-8)asf:f.write(payload)f.flush()os.fsync(f.fileno())os.replace(tmp,path)exceptException:ifos.path.exists(tmp):os.remove(tmp)raisedefadd(title:str,items:list[Item])-list[Item]:titletitle.strip()ifnottitle:raiseValueError(标题不能为空)nidmax((x.idforxinitems),default0)1items.append(Item(idnid,titletitle))returnitemsdefdone(item_id:int,items:list[Item])-list[Item]:forxinitems:ifx.iditem_id:x.doneTruereturnitemsraiseValueError(f没有编号{item_id})defmain()-int:解析子命令成功返回 0用户输入错误返回 2。parserargparse.ArgumentParser(description可恢复的命令行待办)parser.add_argument(--data,typePath,defaultDEFAULT_DATA)commandsparser.add_subparsers(destcommand,requiredTrue)add_parsercommands.add_parser(add)add_parser.add_argument(title)commands.add_parser(list)done_parsercommands.add_parser(done)done_parser.add_argument(id,typeint)argsparser.parse_args()try:itemsload(args.data)ifargs.commandadd:save(args.data,add(args.title,items))elifargs.commanddone:save(args.data,done(args.id,items))else:foriteminitems:markxifitem.doneelse print(f[{mark}]{item.id}:{item.title})return0except(OSError,ValueError,json.JSONDecodeError)asexc:print(f错误{exc})return2if__name____main__:raiseSystemExit(main())在脚本目录执行python todo.py add复核第43期python todo.py add备份 todos.jsonpython todo.py list python todo.py done 1 python todo.py list预期最后两行是[x] 1: 复核第43期和[ ] 2: 备份 todos.json。再关闭终端、从另一个目录执行python D:\ai-learning\issue-43\todo.py list结果应保持不变。需要隔离测试数据时传--data .\sandbox\todos.json不要拿真实待办做破坏实验。七、可复现失败案例项目记录环节记录——构造方式把DEFAULT_DATA临时改成Path(todos.json)分别从两个目录启动故障现象两次添加都成功list却各看到一条不同任务影响用户误以为保存丢失继续操作可能覆盖错误文件最初误判json.dumps没有真正写盘排查顺序打印 cwd - 打印脚本目录 - 搜索同名文件 - 对比绝对路径根因相对路径由 cwd 解释同名文件实际落在两个目录修复默认路径锚定脚本目录同时保留--data显式注入能力复验从两个目录运行都显示相同任务坏 JSON 返回退出码 2 且原文件不变这是“可复现失败案例”不是虚构的生产事故。旧文件若已经散落先备份并对比内容再合并不要看到同名文件就删除。八、实验设计与数据实验使用临时目录不接触真实待办。控制变量是同一脚本和同一输入只改变启动目录、输入合法性或文件内容指标是退出码、目标文件路径、写入前后 SHA-256 与任务条数。用例预期结果成功判据首次list空输出、退出码 0不要求预先创建文件添加中文标题写入 1 条文件为 UTF-8重启可读空标题退出码 2文件哈希与条数不变done 999退出码 2其他任务状态不变内容改成半截[{JSON 解码错误残骸未被覆盖为空列表从两个 cwd 启动读取同一绝对路径输出任务编号和标题一致功能实验必须同时覆盖正常、边界和失败。原子替换的“进程在任意时刻崩溃”不能由一次手工强杀充分证明因此本文只验证临时文件与替换顺序不把它写成绝对不丢数据。生产系统仍需备份、锁和恢复策略。九、常见问题与避坑把所有异常都当首次运行。文件不存在可以返回空列表权限拒绝、JSON 损坏、结构错误必须报告。三者语义不同。用eval解析命令。用户输入会进入代码执行环境。这里用 argparse 的固定子命令未知参数自动拒绝。把完成动作做成删除。输错编号时难以恢复。先改状态真正删除应另设命令和确认。让 ID 等于下标。删除会导致身份漂移。ID 稳定、顺序可变这两个概念要分开。多个进程同时写。os.replace只避免半文件不防最后写入者覆盖前一个。并发需求出现时换 SQLite 或加可靠文件锁。十、平台、系统与库的差异pathlib会处理 Windows 与 POSIX 分隔符代码里不要手拼反斜杠。Windows 上目标文件被某些编辑器占用时os.replace可能因共享模式失败Linux 通常允许替换仍被读取的文件名。两边都必须捕获OSError并保留旧文件。PowerShell、CMD、IDE 和任务计划的 cwd 都可能不同所以路径契约不能依赖终端。单用户单进程 JSON 足够教学多进程写、条件查询和事务出现时应换 SQLite而不是继续给 JSON 打补丁。十一、验证清单执行两次add后运行list应看到稳定编号 1、2。从其他目录以绝对脚本路径运行输出应与脚本目录启动一致。执行空标题和done 999退出码应为 2原文件内容不变。把测试副本改成[{应报告 JSON 错误文件不能被覆盖成[]。完成编号 1 后重启编号 2 不应变成编号 1。用中文标题保存并重开终端与文件中都应显示原汉字。搜索工作区内todos.json除显式测试路径外只应存在约定文件。从单文件练习推导存储边界JSON 方案成立有三个前提单用户、单进程、数据量可一次读入内存。只要其中一个变化设计就要重新评估。两个终端同时加载相同版本各自追加任务再保存后保存者会覆盖前者原子替换只能保证文件完整不能合并两份并发修改。最小改进可以在文件中增加版本号保存前重新读取并做乐观并发检查真正需要并发、条件查询或事务时SQLite 比自制锁协议更可靠。格式也会演进。今天任务只有 id、title、done明天可能增加 created_at、priority。加载器若直接Item(**row)未知字段和缺失字段都会失败。学习阶段可以严格失败迫使开发者写迁移生产升级则应给文件增加schema_version按版本逐级迁移并在迁移前备份。不要用“字段没有就给默认值”悄悄吞掉所有差异因为拼写错误也会被当成旧格式。恢复策略要回答三个问题旧文件保留多久如何识别最近一次有效备份恢复后如何验证。可以在替换前把目标复制为带时间戳的备份但备份本身也要有数量上限且复制失败时不应继续覆盖。本文没有实现轮换是因为备份策略与用户价值、磁盘空间有关这属于适用边界不该用一句“原子写入所以安全”掩盖。命令行接口也有稳定性。退出码 0 表示成功2 表示输入或数据错误人类提示写到标准错误会更便于管道区分机器可读输出可以另加--json不要让脚本解析彩色中文句子。--data是依赖注入点也是测试边界正式路径、测试临时路径和导入旧文件都经同一入口。路径可配置不等于路径随意程序仍应打印解析后的绝对路径让排障者知道正在操作哪份数据。最后用一次恢复演练收口复制测试文件故意截断末尾确认加载失败且原内容没有被写空恢复备份后再次 list编号、标题和完成状态全部一致。演练的证据是文件哈希、退出码和任务数不是“看起来好了”。做到这里单文件工具才真正具备可恢复性而不是只有保存按钮。测试时如何观察“不写盘”失败路径最重要的断言不是错误文案而是状态未被改变。测试可以在临时目录写入一份已知 JSON记录原始字节调用空标题、越界编号或坏结构后再逐字节读取并比较。只比较内存 items 不够因为错误实现可能先把空列表写盘再抛异常。目标文件内容、临时文件残留、退出码三者都要观察。对原子保存的正常路径验证新文件可以再次反序列化、任务数一致、中文未转义丢失并确认目录里没有遗留.tmp。对模拟替换失败的路径可以把 replace 封装成可注入函数由测试让它抛 OSError断言旧文件仍在、临时文件被清理、异常没有被吞。本文代码直接调用标准库读者扩展测试时再做这个小重构避免为了测试把生产逻辑复制一份。数据边界还包括文件权限。只读目录、磁盘空间不足和防病毒软件占用都可能让保存失败。程序应把 OSError 转成人能理解的失败并返回非零退出码绝不能先删除旧文件再尝试新建。Windows 文件占用行为与 Linux 不同这正是为什么“同目录写临时文件并替换”要在目标系统实测。最后区分业务失败与程序缺陷空标题、编号不存在、JSON 损坏属于预期失败可以给简洁提示AttributeError、断言失败等未知缺陷不应被宽泛捕获后伪装成输入错误。捕获范围越小调试线索越完整。稳定的 CLI 不是永不失败而是失败类别清楚、旧数据仍可恢复、自动化调用能从退出码判断下一步。还要验证帮助信息本身python todo.py --help应列出三个子命令和--data未知命令应由 argparse 返回非零退出码且不创建数据文件。命令行契约一旦被脚本调用参数名与退出码就是公开接口修改时要同步 README并保留兼容迁移而不是只让交互演示能跑。十二、面试题与追问为什么不用数据库单人单文件足够先把失败路径走完。追问什么时候必须换存储并发和查询变复杂时。相对路径为什么危险它相对 cwd 不是脚本。追问__file__在 notebook 里可靠吗不可靠要注入数据目录。坏 JSON 该崩溃还是当空应崩溃或备份后提示不能当空。追问为什么当空等于删数据。如何测试 CLI把 add/done/load/save 做成纯函数测试不走 input。追问要不要自动化按键盘先测函数。id 用列表下标行不行删除后错位。追问自增 id 重启后怎么办取 max1。十三、小蓝伞的工程金句写到哪里不能取决于你站在哪里。静默把坏文件当成空列表比崩溃更危险。能关终端再打开还在才叫持久化。十四、本篇技术清单与下一期下一期AI-0132 网页电影信息抓取把第 40 期 requests、第 37 期 JSON、本期文件保存和合规边界接起来。关注合集继续。你的 CLI 数据文件丢过吗是 cwd 还是写到一半先定文件契约再谈功能列表。官方资料https://docs.python.org/zh-cn/3/library/json.htmlhttps://docs.python.org/zh-cn/3/library/pathlib.htmlhttps://docs.python.org/zh-cn/3/library/tempfile.html适用边界学习用单人工具。生产还要备份、权限和并发控制。

相关推荐

软考架构设计师论文 —— 论AI驱动的智能运维架构及其应用(2)
软考架构设计师论文 —— 论AI驱动的智能运维架构及其应用(2)

接前一篇文章:软考架构设计师论文 —— 论AI驱动的智能运维架构及其应用(1) 论题 随着软件系统规模的不断扩大和云计算、微服务架构的普及,运维工作正面临着复杂度高、变化快、实时性要求强等挑战。传统的人工运维方式往往存在效率低、响应慢、容易出错等问题,而DevOps的… · 2026/9/24 17:32:19

Agent Substrate 安全状态报告技能(security-status-report SKILL)实战指南:基于威胁模型驱动的多子代理安全评审流水线
Agent Substrate 安全状态报告技能(security-status-report SKILL)实战指南:基于威胁模型驱动的多子代理安全评审流水线

人工智能AI AgentAgent 沙箱云原生容器运行时零信任 【免费下载链接】substrate Agent Substrate: the core system 项目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate 点击查看 免费下载 导读 security-status-report 是 Agent Substrate 仓库… · 2026/9/24 17:32:19

DeepSeek 企业私有化部署值不值?用 vLLM 算清安全账与成本账(附 config.toml 实操)
DeepSeek 企业私有化部署值不值?用 vLLM 算清安全账与成本账(附 config.toml 实操)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 17:32:07

人脸识别签到系统毕业设计:深度学习特征提取与活体检测完整方案
人脸识别签到系统毕业设计:深度学习特征提取与活体检测完整方案

简介:基于深度学习的人脸识别签到系统,是一份面向计算机专业毕业设计的高分项目源码包,评审分为99分,代码完整且可运行,适合正在准备毕设、课程设计或期末大作业的本科学生,也适合需要项目实战练习的开发者… · 2026/9/24 18:07:17

基于深度学习的舌苔识别系统:Python源码+GUI界面+模型+论文报告全解析
基于深度学习的舌苔识别系统:Python源码+GUI界面+模型+论文报告全解析

简介:这份资源是面向深度学习入门者与计算机相关专业毕业设计学生的舌苔识别检测鉴定系统完整项目包,围绕中医舌象智能分析场景,解决舌苔分类与体质辨识的算法落地问题。包内共110个文件,以Python源码、模型权重文件、UI界面文件、… · 2026/9/24 18:07:10

基于CNN的舌苔识别系统实战:从图像预处理到GUI部署
基于CNN的舌苔识别系统实战:从图像预处理到GUI部署

简介:本资源为基于深度学习的舌苔识别检测鉴定系统完整项目包,面向计算机、人工智能及中医药信息化方向的毕业设计学生与算法入门者,帮助解决舌象分类、体质辨识等课题从选题到落地的全流程需求。包内共110个文件,以Python源码、模… · 2026/9/24 18:07:10

SSM+UniApp外卖系统真机跑通指南:四角色闭环实战
SSM+UniApp外卖系统真机跑通指南:四角色闭环实战

简介:这是一套面向计算机专业本科生毕业设计的微信小程序外卖点餐系统完整源码,基于SSM后端框架与VueUniApp前端技术栈构建,覆盖管理员、餐厅、外卖员、用户四类角色的全业务流程,适用于课程设计、毕设开发与Java/小程序综合实践。… · 2026/9/24 18:07:10

LSTM排放预测实战:从时序切片到在线微调的落地指南
LSTM排放预测实战:从时序切片到在线微调的落地指南

简介:本资源面向本科及以上阶段、具备一定MATLAB基础的学生与研究人员,提供一套基于长短期记忆神经网络(LSTM)的汽车排放量预测完整实现方案。汽车排放数据本质上属于时间序列,相比普通前馈神经网络,LSTM在… · 2026/9/24 18:07:10

ExpertNet+ResNet50医疗图像多任务无监督自适应:原理与完整源码解析
ExpertNet+ResNet50医疗图像多任务无监督自适应:原理与完整源码解析

简介:Python实现的ExpertNet结合Resnet50多任务学习网络源码包,专注于医疗图像无监督自适应分析,适合深度学习开发者、医疗影像研究人员及高年级学生。项目在不依赖大量标注数据的前提下,面向肿瘤识别、病变检测等多任务场景&… · 2026/9/24 18:07:10

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码