真实项目与「别扭点清单」(主线 C)

主线 C 的定位是路线的事实来源:语言缺什么,不是坐在桌前想出来的, 而是写真实程序时撞出来的。本文件记录三件事—— 五个场景各有什么项目、行数比基线是多少、写的时候哪里别扭。

一、五个场景

场景项目干什么用到的语言面
数据处理成绩分析/读 CSV,出总分排名、各科平均与最高、不及格名单表格、文本、闭包、推导式、排序
数据处理日志统计/解析访问日志,出请求数、独立 IP、状态码分布、最热路径、404 IP文件、字典计数、排序、格式化
网页采集网页采集/抓网页 → html.取链接 提链接 → 存 CSV → 域名分布网络、html、正则、表格
CLI 工具待办清单/增删改查 + JSON 持久化 + 命令行参数 + 出错给人话系统.参数、json、文件、时间
算法练习排序跑分/三种排序(冒泡/插入/快排)+ 用内建排序当裁判 + 规模-耗时表递归、推导式、随机、时间
教学演示 / 站点生成基石自述站/用基石读仓库真数据,生成介绍基石的静态站文件、路径(递归列出 / 按模式找)、文本、f-string

另有 examples/tutorial/ 十课作为教学演示的入门线(01 你好 → 10 综合), 不与上表混算行数比。

每个项目都能直接跑,跑法见各自 README.md;tests/test_m15_projects.py 与 tests/test_m39_selfsite.py 把它们钉在测试里(含输入喂给、产物断言)。

二、行数比基线(M40 起点 → 现在)

口径:每个项目里 .jsh 是基石实现,参考实现.py 是只用标准库的 Python 实现,两者同功能、同输出口径;有效行 = 去空行、去纯注释行。 比值 = 基石有效行 ÷ Python 有效行,越小越「方便实现意图」。 表由 python tools/loc_ratio.py --markdown 现算,不是手抄的。

① M40 起点(留着看「降了多少」):

项目场景基石(有效行)Python(有效行)行数比总行比
基石自述站教学演示 / 站点生成2992381.261.26
待办清单CLI 工具113911.241.38
成绩分析数据处理63521.211.17
排序跑分算法练习93671.391.45
日志统计数据处理70451.561.62
网页采集网页采集50491.021.06

合计:基石 688 行 / Python 542 行 → 加权比值 1.27;逐项平均 1.28。

② 现在(2026-10-11,M108 时点):

项目场景基石(有效行)Python(有效行)行数比总行比
基石自述站教学演示 / 站点生成2872381.211.24
待办清单CLI 工具108911.191.33
成绩分析数据处理63521.211.17
排序跑分算法练习82671.221.29
日志统计数据处理53451.181.26
网页采集网页采集48490.981.03

合计:基石 641 行 / Python 542 行 → 加权比值 1.18(起点 1.27); 逐项平均 1.16(起点 1.28)。

📌 降幅最大的正是 M40 复盘里点名的两个:「不是中文不好写,而是缺几件标准库的 顺手工具」—— 日志统计 1.56 → 1.18、排序跑分 1.39 → 1.22。

这个数字不好看,但它是真的,而且是可复核的:口径写在上面,工具在 tools/loc_ratio.py,谁都能重算或换口径重算。它同时给出了 M40 起「逐档下降」 的起点——没有起点就没法说「下降了」。

三个值得注意的点:

基石这一侧反而比 Python 参考实现(html.parser 手写状态机)还短一行。

别扭点 3/4/5——不是「中文不好写」,而是缺几件标准库的顺手工具。

手写循环换成了 路径.递归列出 / 路径.按模式找(少了 10 行有效行)。 它的行数里模板与 CSS 占大头(两边逐字相同),所以这一项更接近「逻辑行」的比较。

为了让基线诚实,tools/loc_ratio.py --check 会检查每个项目是否都配了 Python 参考实现;缺了就报错——避免「只挑对自己有利的项目算」。

三、别扭点清单(写完这批项目攒出来的)

每条都给结论:→ 语法(走准入三关)/ → 标准库 / → 工具 / 明确不做。

#别扭点现场结论
1~~导入 文本 打断所有 f-string~~(✅ M40 已修:插值改用内部保留名 $文本):插值脱糖成 文本(值),模块「文本」正好遮蔽这个内建写 日志统计 时想用 文本.左对齐,一导入 f-string 全报错「模块「文本」不能直接调用」→ 语言(✅ M40 已修):给插值一个不会被遮蔽的内部转换(三宿主同步)。在那之前用 导入 文本 为 别名
2~~转换失败抛「类型错误」,而 Python 是 ValueError~~(✅ M41 已修:文本转不动抛值错误、类型不对才抛类型错误)整数("abc") 抛类型错误 → 写 捕获 值错误 接不住(成绩分析/分析.jsh 里就是这么写的,只是样例数据从没触发)→ 语言(✅ M41 已修):内建 整数/小数 与 "abc".转整数() 归到同一类;待办清单 的 捕获 异常 已收窄成 捕获 值错误
3~~缺 Counter 式的计数字典~~(✅ M41 已修:容器.计数 / 容器.最多 / 容器.按值排序)日志统计:Python Counter(...) 一行,基石要手写「有就加一、没有就置一」 + 自己排序→ 标准库(✅ M41 已修):模块名是「容器」不是「集合」——集合 是内建函数名,同名模块会把内建遮蔽(正是 #1 那类坑)
4~~缺 round 与格式化规格~~(✅ 核实:数学.四舍五入 与 文本.格式化("{:.2f}") 早就有了,是写项目时不知道)排序跑分 要自己写 小数位()(整数(x*100+0.5)/100);Python 一个 round(x, 2) 或 {x:.2f}→ 能力已有但不可发现:排序跑分 已改用标准库(删掉自己写的 小数位());真正缺的是「怎么知道有这个函数」
5下标目标不能解包赋值:结果[j], 结果[j+1] = … 解析失败冒泡交换要写三行(临时变量)→ 语法候选(先记下,不急着做):属于「多目标赋值」的扩展,要走准入三关;目前三行写法不算难读
6~~没有递归列目录~~(✅ M41 已加 路径.递归列出(目录, 后缀),五路同宽)基石自述站 数 examples/ 下的 .jsh 要手写递归(Python 一个 rglob)→ 标准库(✅ M41 已加)
7~~命令行「子命令 + 参数」要手写~~(✅ M41 已加 参数 模块)待办清单 自己解析 系统.参数()、自己打印用法→ 标准库(✅ M41 已加):选项式解析(--名字 值 / --名字=值 / --标志)交给模块;待办清单 那种子命令式仍要自己分发(模块只管选项,不管子命令)
8~~字符串对齐/补零在 文本 模块里很好用,却撞 #1~~(✅ 可用:排序跑分 已改用 文本.左对齐,用别名导入避开遮蔽提示)排序跑分 的表格对齐只好手写 对齐()✅ 已用上
9字典.获取(键, 默认) 很好用(真实项目里反复用)—保持:这是正面例子,写进语言卡
10如果 … 否则 … 表达式(条件表达式)在数据整理里很顺手令 标记 = "√" 如果 完成 否则 " "保持:M36 的脱糖路线收益在这里体现出来了

十条里只有 2 条与语法相关(#1 是「既有语法的正确性」、#5 是候选), 其余都是标准库能解决的——这与「语法面已冻结、新需求先问能不能用 标准库」的结论一致。

M41 收口后的复盘

十条里 7 条已解决(#1/#2/#3/#4/#6/#7/#8),1 条转成「能力已有但不可发现」 (#4/#8:数学.四舍五入、文本.左对齐、集合 的交并差早就存在,是写项目 时不知道),只有 #5(下标目标解包赋值)还留在语法候选。

这暴露了一类新问题:真实项目里卡住的未必是「语言缺能力」,也可能是 「有但找不到」。M42–M45 的两个外功方向(IDE 补全 / AI 语言事实)正好治它。

顺带补上的两条(清单之外)

(临时循环变量 + 循环体首句解包赋值),三执行器与两宿主零改动。 原先只有 令 甲, 乙 = … 支持解包,遍历 不支持——examples/ai/few-shot.md 的示例 34 就是这么写错的(见下条)。

写法」样本,但从没人跑过。逐段执行发现 4 段真错(用了不存在的语法或 API),已修;并加了 tests/test_m41_stdlib.py 的逐段测试钉住——片段 不自包含的按「环境缺失」放行,语法/API 错误必须报出来。

三之二、绕道探针与台账(M105 起,2026-10-11)

上面那十条是 M40 时代的清单 —— 写法是「写完项目再回头总结」。M105 起换了做法: 条目写在撞到它的那个地方(项目自己的 README.md 里),台账由脚本扫出来。 这样它不会与代码脱节(补了没更新、删了还留着)。

东西在哪说明
探针项目examples/绕道探针/用现有标准库尽力写的真实小程序;不要求功能完整,所以不放在 examples/projects/,也不参与行数比
台账docs/绕道台账.md扫出来的,别手改
生成 / 自检python tools/detour_ledger.py加 --check 只自检、不写文件
判据tests/test_m105_detour_ledger.py台账与探针一致 · 自检真的会红 · 探针真能跑

⚠️ 台账会「过期报红」:某条写着「缺 文本.左对齐」,而那个函数已经有了时会自检失败 —— 逼着人去把条目消掉或改写,而不是让台账慢慢烂掉。 (同 AGENTS.md 的纪律:「豁免必须显式、可复核、会过期报红」。)

探针当前扫出 7 条,撞出来的东西与「值多少」都写在 docs/绕道台账.md 里。

四、怎么跑

bash# 各项目(在项目目录里跑,数据文件也在那儿)
jishi 分析.jsh           # 成绩分析:用 成绩.csv
jishi 统计.jsh           # 日志统计:用 访问.log
jishi 采集.jsh           # 网页采集:会问网址
jishi 待办.jsh 列出       # 待办清单
jishi 排序.jsh           # 排序跑分
jishi 生成.jsh           # 基石自述站:生成到 site/基石自述/

# 行数比基线(本项目根目录)
python tools/loc_ratio.py
python tools/loc_ratio.py --markdown     # 贴文档用的 Markdown 表
python tools/loc_ratio.py --check        # 检查每个项目都配了 Python 参考实现

三个执行器都能跑这些项目(jishi 脚本.jsh --执行器 vm);基石自述站 的产物 在三个执行器下逐字节相同(tests/test_m39_selfsite.py)。