Day 11 这个标题放到熟悉编程打卡圈的人眼里基本就是“100 Days of Code”挑战中途的一个节点。连续记录了十个学习日之后很多人会在这一天迎来第一波真正的倦怠和挫败——新鲜感已经用完难度开始爬坡放弃的念头变得异常具体。我自己的第十一天就是这么过来的当时前十天跟着教程敲了不少案例但合上教程自己独立面对一个需求时脑子是空的。于是我把 Day 11 定成了“第一次组合型项目日”不学新东西只用前十天学到的知识从头到尾做一个能解决实际问题的工具。这篇记录适合三类人正在做类似“百日计划”“三十天进阶”的坚持型学习者刚学完 Python 基础但不知道怎么落地的小白以及已经有一定基础、想看看别人怎么拆解一个小项目的业余开发者。Day 11 的主角是一个自动整理下载文件夹的脚本看起来很小但它把文件路径操作、类型判断、异常处理、日志打印、命令行参数这些零散知识点串成了一条完整的链。整个过程一整天踩了不少坑也留下了一些很值得说的经验。1. 为什么 Day 11 是绝大多数挑战者折戟的地方1.1 “第十一天陷阱”是怎么发生的做长期学习挑战的人都知道前三天是兴奋期每天都有新知识打卡特别起劲到第五六天新鲜感开始打折到了十天左右会出现一次明显的心理低谷。我管它叫“第十一天陷阱”因为第十天刚好是一个心理上的小节点——你已经打卡两位数了回头看发现会的东西还是很有限看向前又觉得要学的东西茫茫多。这种落差感在数据上也说得通。大多数教程的前半段都在讲基础语法、数据类型、控制流这些内容单独看都很简单但真实场景往往是多块知识点同时用。你学过了 os.path 操作路径学过了 for 循环遍历列表学过了 if 判断分支但没人教你“当一个路径不存在时是直接跳过还是报错”。教程里每个知识点都有标准答案现实中的问题没有标准答案。第十一天正好卡在“从标准答案走向开放问题”的临界点上放弃的人不是笨是还没适应这种思维转换。这一天的另一个麻烦在于身体和习惯层面。到第十一天刚开始时的冲劲耗完了但新的自动化习惯又还没完全固化。下班后、写完作业后打开编辑器的一瞬间会有明显的拖延感心里想的不是“今天要学点什么”而是“要不今天休息一下”。这种念头一旦开个头后面几十天基本就是名存实亡。1.2 这一天的策略调整从学知识转向做项目面对第十一天陷阱我做的第一个调整是改变当天的目标类型。前面十天每天的目标都是“学会某个知识点”比如“学会用列表推导式”“学会读写文件”。这种目标的问题是知识点之间没有连接学完就忘也很难带来成就感。第十一天我把目标换成了“做完一个完整的小工具”并且这个工具必须能解决我自己的真实问题。真实问题不存在标准答案这恰恰是它有价值的地方。为了完成它你不得不自己去拆解需求、自己决定数据结构、自己处理各种边界情况。这个过程比看十节教程都长进得快。我选中的问题是“整理下载文件夹”——因为我的 Downloads 目录已经乱成一锅粥了PDF 和截图混在一起安装包和音乐文件全堆在同一个层级每次找个文件都要翻半天。选这个项目还有一个私心它能形成正反馈。脚本第一次跑完看着原本乱七八糟的目录被分门别类地规整好那种满足感比完成一节练习题强多了。对处于疲软期的学习者来说即时的正反馈比什么都重要。1.3 项目选题的三个硬性标准给同样处于瓶颈期的人一个可以参考的选题标准。第一项目必须能在三到五个小时内完成主体功能半天时间的投入刚好不会让本就很累的你更难启动第二项目必须全部使用已经学过的知识项目期间不引入新的语法概念只把旧知识组合出新花样第三项目完成后必须立刻有效果它整理的是一份真实的文件、是一份真实的数据而不是练习题里虚构的案例。我当时还把“可控性”也算进了标准里。所谓可控就是项目出问题时你能一眼看出哪里坏了。整理文件的脚本每一步都能通过打印日志观察运行过程非常适合新手做第一个组合型项目。2. 核心细节解析与实操要点2.1 需求拆解把“整理文件夹”变成可执行的功能点“整理下载文件夹”这句话听起来简单真动手时才发现无从下手。任何一个含糊的需求落成代码前都先要拆成明确的功能点。我拆完长这样扫描目标目录列出所有文件根据文件扩展名判断它属于哪个分类在目标根目录下创建分类文件夹把文件移动到对应的分类文件夹如果遇到了同名文件自动加序号不做覆盖处理完之后输出一份统计报告告诉你每个类别有多少文件。这六个功能点就是整个脚本的最小闭环。拆到这一步后面写代码就不再是“凭空写程序”而是逐条实现清单。我在 Day 11 学到的最大方法论就是这个需求拆解得越细写起来越顺畅。以后做任何项目哪怕很大我都是先列功能点清单而不是直接打开编辑器。2.2 技术选型背后的理由技术方案上我特意只用 Python 标准库没有装任何第三方依赖。原因有两个一是 pip 安装额外的库在有些环境里会遇到网络超时、版本冲突的问题对一个刚刚建立信心的项目来说这类附加成本能省则省二是文件整理这个场景标准库已经完全够用。核心用的是 pathlib、shutil、collections 和 argparse 这几个模块。选 pathlib 而不是 os.path是因为 pathlib 的 Path 对象更直观用.suffix直接拿文件扩展名用.iterdir()遍历目录返回的每一项都是 Path 对象可以直接继续调方法。命令行参数这块argparse 虽然写起来略啰嗦但它自带--help参数缺省时报错信息也清楚对新手比手动解析 sys.argv 友好得多。有一个取舍值得说一说分类规则我用的是一个普通的字典映射没有用配置文件。像“把 jpg 归类到图片”这种规则如果以后想调整改代码里的字典就行。对个人小工具来说保持简单比搞得过度工程化更重要。2.3 安全边界为什么必须设计预演模式文件移动操作有一个致命风险一旦代码写错可能把文件移动到不该去的地方。所以我从一开始就设计了两种运行模式。默认为 dry-run 预演模式脚本只打印“准备移动 A 到 B”但实际不动任何文件只有显式传入参数后才会真正执行移动。这个设计拯救了我好几次。第一次跑预演模式发现我把目标根目录设置错了脚本准备把下载里的所有文件移动到系统盘根目录去。如果直接运行真实模式后果不堪设想。安全边界这个思路对所有操作类脚本都适用不只是整理文件。凡是会修改数据的操作第一步都应该是“只读预览”确认无误后再真正执行。3. 实操过程与核心环节实现3.1 先写扫描与分类我习惯从“骨架”开始写也就是先建立一个最小的可运行程序再往里面加功能。第一个版本只有目录扫描和文件打印from pathlib import Path downloads Path.home() / Downloads for item in downloads.iterdir(): if item.is_file(): print(item.name, item.suffix)这里有个细节item.is_file()只在 item 是一个文件时返回 True目录会被排除在外。如果要做更严格的处理还可以顺便跳过以.开头的隐藏文件避免把.DS_Store之类的文件也当普通文件处理。运行完这版看到屏幕上刷出了一长串文件名和扩展名算是给项目开了个好头。3.2 分类规则的实现拿到文件列表后下一步是根据扩展名分类。我建了一个扩展名到分类名的映射字典然后用dict.get()做查询。未知的扩展名统一放进“其他”这个兜底分类防止任何文件被遗漏在移动列表之外。EXTENSION_MAP { .jpg: 图片, .jpeg: 图片, .png: 图片, .gif: 图片, .mp3: 音频, .wav: 音频, .flac: 音频, .mp4: 视频, .mov: 视频, .mkv: 视频, .avi: 视频, .pdf: 文档, .doc: 文档, .docx: 文档, .txt: 文档, .md: 文档, .xls: 表格, .xlsx: 表格, .csv: 表格, .zip: 压缩包, .rar: 压缩包, .7z: 压缩包, .tar: 压缩包, .gz: 压缩包, } def classify(file_path): ext file_path.suffix.lower() return EXTENSION_MAP.get(ext, 其他)每次调用file_path.suffix都新拿一次扩展名所以统一用 local 变量读好需要时再用。把扩展名转成小写再查表是为了处理.JPG和.jpg的差异。这个看起来不起眼的细节在实际的下载目录里几乎是必然遇到的。3.3 移动逻辑与同名冲突处理移动文件的核心逻辑不复杂用shutil.move就行。真正需要动脑子的是冲突处理目标文件夹里已经有同名文件时怎么办直接覆盖太危险。报错终止又太脆弱。我采用的是“自动追加序号”策略检查目标路径是否存在如果存在就在文件名末尾加_1、_2直到路径可用为止。import shutil from pathlib import Path def unique_path(dest: Path) - Path: if not dest.exists(): return dest stem, suffix dest.stem, dest.suffix counter 1 while True: candidate dest.with_name(f{stem}_{counter}{suffix}) if not candidate.exists(): return candidate counter 1with_name这个方法是生成同名新路径的简便写法不需要手工拼接字符串。这个函数保证了即使一个目录里有一百个report.pdf也能全部保住不会互相覆盖。3.4 完整脚本与一次真实运行记录把所有功能组合起来加上 dry-run 模式和日志输出完整脚本长这样import argparse import logging import shutil import sys from collections import defaultdict from pathlib import Path EXTENSION_MAP { .jpg: 图片, .jpeg: 图片, .png: 图片, .gif: 图片, .mp3: 音频, .wav: 音频, .flac: 音频, .mp4: 视频, .mov: 视频, .mkv: 视频, .avi: 视频, .pdf: 文档, .doc: 文档, .docx: 文档, .txt: 文档, .md: 文档, .xls: 表格, .xlsx: 表格, .csv: 表格, .zip: 压缩包, .rar: 压缩包, .7z: 压缩包, .tar: 压缩包, .gz: 压缩包, } def classify(file_path: Path) - str: ext file_path.suffix.lower() return EXTENSION_MAP.get(ext, 其他) def unique_path(dest: Path) - Path: if not dest.exists(): return dest stem, suffix dest.stem, dest.suffix counter 1 while True: candidate dest.with_name(f{stem}_{counter}{suffix}) if not candidate.exists(): return candidate counter 1 def organize(src_dir: Path, dest_root: Path, dry_run: bool) - None: stats defaultdict(int) moved 0 failed 0 for item in src_dir.iterdir(): if not item.is_file() or item.name.startswith(.): continue category classify(item) target_dir dest_root / category target_dir.mkdir(exist_okTrue, parentsTrue) dest unique_path(target_dir / item.name) stats[category] 1 if dest item: logging.info(fSKIP: {item} 已在目标目录跳过) continue if dry_run: logging.info(f[DRY RUN] {item} - {dest}) continue try: shutil.move(str(item), str(dest)) moved 1 except OSError as e: failed 1 logging.error(f移动失败: {item} - {e}) logging.info(f统计结果: {dict(stats)}) if not dry_run: logging.info(f成功移动 {moved} 个文件失败 {failed} 个) def main(): parser argparse.ArgumentParser(description自动整理下载文件夹) parser.add_argument(--src, defaultstr(Path.home() / Downloads), help源目录) parser.add_argument(--dest-root, defaultstr(Path.home() / Downloads), help目标根目录) parser.add_argument(--real, actionstore_true, help真实执行移动默认是预演模式) parser.add_argument(--log-level, defaultINFO, help日志级别) args parser.parse_args() logging.basicConfig(levelargs.log_level, format%(asctime)s %(levelname)s %(message)s) src_path Path(args.src) if not src_path.is_dir(): logging.error(f源目录不存在: {src_path}) sys.exit(1) dest_root Path(args.dest_root) organize(src_path, dest_root, dry_runnot args.real) if __name__ __main__: main()第一次运行的时候我用的还是默认参数日志里显示一个 PDF 文件被判定为“文档”准备好移动到/Downloads/文档/report.pdf一切正常。但接着往下看我发现有个.part结尾的未下载完文件被放进了“其他”。虽然不算 bug但这启发了我再处理一步对这类“半成品”文件也可以在日志里给出提醒看看是不是下载任务没结束。真正执行是在确认预演结果没问题之后。那次真实运行从扫描到移动总共处理了 94 个文件跑了不到一秒。执行完看到原本塞满上百个文件的目录清爽了很多那种“代码改变了真实世界”的实感非常强烈。3.5 从一次性脚本到顺手工具完成主体功能后我又加了几个对个人使用很实用的功能。一是可指定源目录和目标根目录这样不只 Downloads桌面或者网盘同步目录也能用它整理二是日志格式带时间戳方便回溯三是默认不删除任何文件只移动不删除虽然少了一些“自动化清洁”的能力但对新手项目来说保守比激进安全。这个脚本到现在我还偶尔用把它从“Day 11 的练习”升级成了“日常工具”这本身就是坚持做项目的最大回报。4. 常见问题与排查技巧实录4.1 新手做文件操作类项目必踩的五个坑我把这个项目前后踩过的坑整理成了速查表任何一个刚动手做文件操作类项目的朋友都可以直接抄走问题表现排查与对策路径带空格移动时FileNotFoundError所有路径用 Path 对象处理不要手动拼接字符串文件被占用PermissionError: [Errno 13]确认源文件没在打开状态捕获 OSError 后跳过并计数中文文件名乱码控制台打印乱码或移动失败大多数场景下 pathlib 已能正确解析必要时检查系统区域设置隐藏文件或系统文件误处理目标目录出现.DS_Store等扫描时跳过以.开头的文件文件名冲突被覆盖原文件莫名消失移动前用exists()判断同名的自动加序号表格里每一项我都真实遇到过。尤其是路径带空格那一条最开始的版本我用str(item) / str(dest)拼路径一旦目录带空格就报错。改用 Path 对象之后就再没出现过这种问题因为 Path 的运算符重载帮你处理了路径分隔符的细节。4.2 一次真实翻车现场项目做到中途我遇到的第一个严重 bug 是移动时报SameFileError。这个错误的本意是源文件和目标文件是同一个文件不需要移动。但我的场景是源目录和目标根目录在同一个父目录下目标分类目录就是源目录的子目录shutil 在判断时犯了迷糊。当时的处理是加了一个前置判断如果目标路径和源路径相等直接跳过并打印 SKIP。这不算最优雅的解法但对个人脚本来说在日志里明确看到“已跳过”比莫名其妙抛异常要舒服得多。排查这个 bug 的过程我也推荐所有人练习一下不要盯着代码干瞪眼先看异常堆栈的最后一行然后往日志里加打印把源路径和目标路径都输出出来对比。我自己看一眼就明白了问题出在路径相等上问题定位全程不到五分钟。4.3 学完基础但做不出项目的通用破解法Day 11 之前我觉得“会写代码”和“会做项目”是同一件事这个项目做完才发现完全是两码事。如果你也卡在“基础学完了但什么都不会做”的尴尬期我的建议是找一件特别小、特别愚蠢、但真实存在的机械化任务比如整理文件、批量改文件名、给图片加水印、统计一份文本里的高频词。把它做出来什么都别管先跑通。跑通之后你会发现后面要做的事自然浮现出来了怎么让脚本快一点怎么让输出好看一点怎么让它可以处理更多类型的输入。这就是项目的自然增长不是靠硬规划堆出来的。Day 11 的核心奇迹不在于脚本本身多牛而在于它完成了从“跟着别人写”到“自己决定写什么”的转身。5. Day 11 带来的认知升级与后续计划调整5.1 从“讲得清”到“做得成”的分水岭知识类和技能类学习的最大差别在于反馈回路。看完一节教程、听懂一个概念大脑会给你一个“我学到了”的错觉但真正动手做项目时每个环节都在逼你承认“我其实还没掌握”。Day 11 的项目让我第一次清晰看到自己的短板路径处理和异常处理的基础还算扎实但对文件元数据的使用、对不同操作系统的文件行为差异几乎一无所知。短板暴露出来并不可怕可怕的是永远不知道短板在哪。一个很直观的变化是前十天的打卡里每天结束我都觉得自己“又多了一点东西”而从 Day 11 开始我每天晚上都会发现自己“又少了一个不会的坑”。这两种感受的含金量完全不同。5.2 对后续挑战计划的具体建议完成 Day 11 后我连夜改写了后面几十天的计划。原来排的是“今天学 requests明天学 BeautifulSoup后天写爬虫”这种按工具链组织的结构改成了“做三个能解决自己问题的小项目”这种按场景组织的结构。每个小项目只引入一个新知识点其他全部用旧知识解决。这样既不会因为知识负担太重而卡停又能在做的过程中自然补上新工具的使用经验。具体的调整是给每个项目设定一天期限完成一个就给挑战记录画一个里程碑。如果遇到三天都做不完的“超大目标”就果断拆成多个小阶段拆出来的子项目也必须是能独立交付的。5.3 给同样身处 Day 11 的挑战者的几句实在话如果你正处在类似节骨眼上我的建议下面几条应该用得上。一别去追求“做完一个完美的项目”第一天能跑到百分之七十的效果就是胜利剩下的要通过后续版本迭代出来。二中途卡住超过二十分钟就先把代码放一边去写注释、画草稿、跟人讲一遍你卡在哪给大脑一个离线整理的时间。三这个阶段最忌讳到处搜“最佳实践”先把大局观建立起来优化它的机会未来多的是。我不骗你说“坚持就一定成功”因为这种话说多了没营养。但我可以负责任地说第 11 天完成那个整理脚本之后我整个挑战项目里再没有遇到过比“不知道从哪里开始”更让我焦虑的时刻。因为这个坎一旦跨过去后面的路就是具体的、看得见的哪怕是难也是那种“知道下一步要干嘛”的难。最后再分享一个小技巧。当时我把这个脚本放在了一个项目目录下每次觉得学习状态不好就打开它看看 — 看那个分类以后的下载目录盯上几秒钟能立刻想起来“原来我也能做出实实在在的东西”然后坐回去继续写。人在低谷期需要的不是更多鸡汤而是一个能证明自己有完成能力的铁证。我把这个铁证归档成文件这就是 Day 11 留给我最值钱的东西。
企业数字化 ERP 产品动态
相关推荐
微信小程序AI类目审核通关指南:深度合成合规与算法备案实操 1. 这不是“加个AI按钮”就能过审的活儿:先搞懂微信小程序对「AI创作/深度合成」类目的真实态度你是不是也遇到过这样的弹窗?——在微信小程序后台提交审核时,系统突然跳出一行红字:“你的小程序涉及提供文本深度合成技术… · 2026/9/26 21:14:57
网站打不开?从DNS到数据库的层次化故障排查SOP 1. 先别急着刷新:把"网站打不开"拆成五类场景我得先说实话:绝大多数"网站打不开"的求助,最后查出来的根因都不是什么惊天大坑,反而越是简单的故障,越容易被紧张的排障过程搞复杂。凌晨两点收到告警… · 2026/9/26 21:14:57
WeKnora企业级知识中枢:生产就绪的RAG架构与部署实践 1. WeKnora到底是什么?不是另一个RAG玩具,而是腾讯打磨过的生产级知识中枢WeKnora这个名字最近在技术圈里冒头的频率越来越高,尤其在需要快速构建企业级知识服务的场景里。它不是那种写着“支持RAG”就完事的玩具型框架,而是腾讯内… · 2026/9/26 21:14:57
ax:面向AI负载的Kubernetes拓扑感知调度增强层 1. 项目概述:从“ax”这个极简标题看一个现代云原生调度框架的底层逻辑你搜“ax”,第一反应可能是某个缩写、某个变量名,甚至怀疑是不是输错了。但最近在云原生和AI基础设施圈子里,“ax”正悄然成为高频暗语——它不是某个商业产品… · 2026/9/26 21:57:52
HK-20103三通道脉搏信号读取与对齐实战指南 简介:本资源是一套面向生物医学信号处理初学者与教学实践者的三通道脉搏信号分析入门工具包,聚焦HK-20103三通道脉象传感器实采数据的读取、解析与可视化。资源提供Python与MATLAB双平台实现方案:核心含1个Python脚本(read.py&… · 2026/9/26 21:57:52
从散乱渠道到统一作战台:DeskcommCRM客服工作台落地全解析 “DeskcommCRM”这个项目名字,乍一看像是个普通的客户管理系统,但真正把它拆开来看,你会发现它更像是给客服团队和销售团队准备的一张“作战指挥台”。我最早接触这个项目,是因为团队里七嘴八舌的消息渠道实在管不过来了——微信、… · 2026/9/26 21:57:45
de4dot-netcore:.NET Core元数据修复与反混淆实战指南 简介:本资源为适配.NET Core环境的开源脱壳工具de4dot-netcore正式构建版本,面向安全研究人员、逆向工程师及.NET平台开发者,专用于剥离ConfuserEx、DNEmu、.NET Reactor等主流保护壳,还原被混淆或加密的.NET Core程序原始逻辑&am… · 2026/9/26 21:57:45
以沟通为中心的CRM:如何用自动记录终结数据录入难题? 做CRM选型的朋友,应该都见过这种场面:销售总监在周会上摊开一张表,问“这个月商机到底卡在哪个环节”,一线销售低头翻手机,回了句“系统我还没来得及填”。会议室安静三秒,所有人都知道问题出在哪ÿ… · 2026/9/26 21:57:45
Delphi TCP聊天系统实战:服务端长连接、协议解析与离线存储 简介:这是一份面向Delphi初学者与中级开发者的学习型源码资源,聚焦实时网络通信与桌面聊天系统开发实践。资源完整呈现了基于Delphi构建的实景聊天系统v3.0全量工程代码,涵盖登录认证、多线程消息收发、TCP/UDP网络模块、用户界面交互及SQLit… · 2026/9/26 21:57:45
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46