1. 需求拆解:把“我好像掉头发”变成能比较的数据
“秃头日记”这四个字,我最早写在自己手机备忘录里,纯粹是为了吐槽。那天洗完头,地漏上那一坨头发让我沉默了好几秒,我掏出手机拍了张照,命名“秃头日记(1)”,打算每天拍一张,攒上一个月看看趋势。结果一个月后翻相册,我彻底傻了——三十多张照片角度不同、光线不同、头发干湿不同,我连哪张是哪天拍的都得靠文件名猜,更别说判断到底变好还是变坏了。
这个原本只打算当情绪出口的相册,后来被我从头改成了一个正经的小项目:补上数据结构、采集规范、可视化面板和一套判断逻辑。现在它每天提醒我打卡,每周出一张趋势图,每月第一周让我做一次对照复盘。这篇就把这东西从需求到落地完整拆一遍。
先划清边界:这不是一份教你“如何治脱发”的教程,我不会给任何处方建议,涉及具体的医学判断一律建议找专业人士。它解决的是更靠前的一步——你连自己是变快了还是变慢了都说不清,就没法评估任何干预到底有没有用。这个项目适合三类人:被掉发焦虑困住但不知道该记录什么的、已经开始做某件事却没法评估效果的、以及想练手一个完整数据小项目的开发者。
1.1 焦虑为什么解决不了焦虑
我先说个自己踩过的坑。刚开始那两周,我每天早上起来第一件事就是照镜子看发际线,然后越看越焦虑,越焦虑越想看。问题是这种观察本身极不可靠:你天天看同一个东西,视觉系统会自动适应,两毫米的细微变化在你眼里要么被放大成“完了”,要么被压缩成“好像还行”,全看你当天的情绪。
更要命的是采集条件完全不受控。今天洗了头,地漏上一堆;明天没洗,看起来就“少了”。周末熬夜喝酒,第三天掉发明显增多;换季那两周,本来就有个自然的波动周期。这些变量混在一起,你观察到的任何一个“变化”都可能只是噪声。
我后来想明白一件事:真正的问题不在于掉不掉头发,而在于我把一个连续变量当成了二元开关在用。它要么“正常”要么“不正常”,中间没有任何刻度。要让它变得可判断,需要做三件事:把采集条件固定住、把观察周期拉长、用多个指标互相校验。这三件事说起来简单,但每一条在落地时都有具体的坑,下面逐个拆。
1.2 字段设计的核心原则:三十秒能填完
我最初设计的记录表有二十多个字段,包括饮食详情、心情评分、运动类型、洗发水用量估计……结果第一周认真填,第二周开始挑着填,第三周直接放弃。这件事给我一个很深的教训:任何需要超过三十秒才能填完的记录表,注定活不过一个月。
重做的时候我砍到只剩七个必填字段加三个选填,原则很简单——只保留“明天还愿意填”的信息。评估某个字段该不该留,我问自己三个问题:这个信息一周内会变吗?如果不记录,事后能靠回忆补上吗?它能不能和其他字段交叉验证?三个问题里有一个答“否”,就砍掉。
| 字段 | 类型 | 必填 | 为什么需要它 | 填写要点 |
|---|---|---|---|---|
| 日期 | 文本(YYYY-MM-DD) | 是 | 所有分析的主键,必须严格唯一 | 用补零的 ISO 格式,排序才不会乱 |
| 是否洗头 | 布尔 | 是 | 掉发量最大干扰源,分析时必须分组 | 洗了就勾,不洗不勾,不许模糊 |
| 洗头掉发档位 | 枚举 0-4 | 洗头时必填 | 核心观察指标,但只记档位不记根数 | 凭整体印象估档,别数 |
| 枕头掉发 | 枚举 0-2 | 是 | 和洗头掉发交叉验证,防止单点误判 | 起床后看一眼枕面,五秒搞定 |
| 头皮状态 | 枚举 | 是 | 判断是否和清洁度、出油相关 | 油 / 干 / 正常三选一 |
| 睡眠时长 | 数值 | 是 | 最容易被忽略但影响很大的变量 | 估到 0.5 小时精度就够 |
| 特别事件 | 文本 | 否 | 用来解释异常点,事后排查全靠它 | 换洗发水、熬夜、出差、换枕套 |
| 照片编号 | 文本 | 否 | 关联当天的图像证据 | 与归档文件名对应 |
| 备注 | 文本 | 否 | 兜底放临时的主观感受 | 想写就写,别强迫 |
这里有个反直觉的决定:掉发量不数根数,只记档位。我试过认真数,第一次数了四十多根,数到一半就开始怀疑自己有没有数重。数根数是一种伪精确,它给你一种“我有数据了”的错觉,实际上误差可能超过百分之三十,而且极其消耗耐心,是劝退的头号杀手。用“无 / 少量 / 中量 / 偏多 / 明显多”五档,凭整体印象给个判断,虽然粗,但一致性反而更高——同一个人用同一套标尺,跨时间的可比性比精确数字强得多。
1.3 技术选型的三个硬约束
选型这件事我没纠结太久,因为需求本身给了三条很硬的约束:
- 记录必须在手机上三分钟内完成,不然坚持不了;
- 照片必须本地存,这类内容我不想放到任何在线服务里;
- 分析逻辑必须能随时改,因为判断标准会随着数据积累不断调整。
我对比了几种方案,直接上表:
| 方案 | 上手成本 | 可定制性 | 移动端体验 | 数据掌控 | 适不适合我 |
|---|---|---|---|---|---|
| 电子表格 | 极低 | 低 | 差 | 高 | 前期试水可以,后期分析太痛苦 |
| 笔记类工具 | 极低 | 极低 | 好 | 中 | 记录行,分析不行 |
| 自建小程序 | 高 | 中 | 好 | 看实现 | 为了一个个人项目不值得 |
| 本地 Python + SQLite + 可视化 | 中 | 极高 | 需另做入口 | 高 | 最终选择 |
最后落地的架构是双端分离:手机端只负责“录入”,用一个极简的本地网页表单,数据存浏览器本地,攒够几天后一次性导出;桌面端用 Python + SQLite 做存储和分析,照片走本地目录归档。这样手机端足够快,桌面端足够灵活,中间靠一份 JSON 或 CSV 做桥梁。
2. 数据采集:把“感觉”变成可比对的样本
2.1 每日打卡的最小闭环
打卡流程我反复优化过好几轮,现在稳定在九十秒左右,具体是这样走的:
早上起床,先看一眼枕头,勾掉“枕头掉发”档位。这一步五秒钟,关键是别把枕头抖了再去看,那就什么都看不到了。然后打开手机上的记录页,填日期(默认当天)、是否洗头、睡眠时长。如果洗头,洗完吹干后补填掉发档位;如果不洗,这一项留空而不是填零——留空和填零在分析里含义完全不同,前者是“没观察”,后者是“观察了且没有”。
最后是拍照环节,如果当天洗头就拍,不洗就不拍。我给自己定的规则是只在洗头日拍照,因为干湿状态统一了才能横向比,而且把拍照频率从每天降到两三天一次,执行阻力小很多。
这套流程听起来琐碎,但它有个关键特性:每一步都是独立可完成的。哪怕今天再累,只填个枕头档位也算完成最低记录,不会因为“没法完整记录”而干脆全放弃——这是我被断档坑过之后才悟出来的。
2.2 拍照这件事,标准比设备重要
我一开始以为拍照要靠好设备,后来发现完全不是。同一部手机,只要把四个变量固定住,出来的照片可比性远高于换来换去的高端机。
光线固定:永远在同一个位置拍,同一盏灯,不要开窗靠自然光,因为阴天晴天差异巨大。我是在卫生间镜前拍的,那盏灯常年开着,色温稳定。
角度固定:这是最容易漂移的变量。我的办法很土但有效——在镜子上贴一个不起眼的记号,手机摄像头对准记号,机身靠住镜子边缘。这样每次的机位误差能控制在一两厘米内。有条件的话用个小三脚架更稳。
距离固定:机位固定了距离自然就固定了,这也是为什么要靠住镜子,而不是举着手机凑。
分区固定:我每次拍三个区——发际线正面(额头完全露出)、头顶(低头四十五度俯拍)、两侧鬓角。三个区各拍一张,宁可多拍一张也别少拍,因为后期想补是补不回来的。
注意:不要在照片上做任何后期修饰,不要用美颜,不要裁剪后覆盖原图。所有加工都应该是“复制一份再处理”,原图永远保留。我吃过亏,有一批照片被批量压缩过,细节全丢了,那段时间的数据基本作废。
2.3 数据质量控制里最容易翻车的四个坑
坑一:洗头频率变了却没记录。这是最隐蔽的干扰源。有段时间我改成隔天洗,结果洗头日的掉发档位整体上跳了一档,我差点以为情况恶化了,翻回去才发现是频率变了。所以“是否洗头”这个字段必须是强制的,分析时也永远按洗头日 / 非洗头日分组看,绝不能混在一起。
坑二:短周期对比。掉发本身有周期性波动,一周之内的起伏基本没有意义。我一开始每天看曲线,情绪跟着曲线走,后来强制自己只看四周滚动值,世界立刻清净了。
坑三:照片角度悄悄漂移。记号贴久了会掉,掉了你没注意,机位就慢慢偏了。我的做法是每两个月检查一次记号位置,并且每个月抽一张和上个月的同分区照片做叠图比对,偏了能看出来。
坑四:记录热情衰减。前两周几乎百分百记录,第三周开始漏,第五周一周只记了两天。这个不是意志力问题,是设计问题——后来我加了提醒和“最低可接受标准”(一周至少四天),情况才好转。这块在第 5 章细讲。
3. 从零实现:核心模块与代码落地
3.1 数据表设计:先想清楚怎么查,再想怎么存
建表之前我先列了三类查询:按时间看趋势、按洗头分组求中位数、按事件标记找异常点。围绕这三类查询反推表结构,最后定下来核心表就一张,加一张照片表。
CREATE TABLE IF NOT EXISTS daily_log ( log_date TEXT PRIMARY KEY, -- ISO 格式,YYYY-MM-DD washed INTEGER NOT NULL DEFAULT 0,-- 0 未洗 / 1 洗了 shed_level INTEGER, -- 0-4,未洗头日为 NULL pillow_level INTEGER, -- 0-2 scalp_state TEXT, -- oil / dry / normal sleep_hours REAL, events TEXT, -- 逗号分隔的标签 photo_id TEXT, note TEXT, created_at TEXT DEFAULT (datetime('now','localtime')) ); CREATE TABLE IF NOT EXISTS photo ( photo_id TEXT PRIMARY KEY, -- 如 20240501_top_01 log_date TEXT NOT NULL, zone TEXT NOT NULL, -- front / top / side path TEXT NOT NULL, FOREIGN KEY (log_date) REFERENCES daily_log(log_date) ); CREATE INDEX IF NOT EXISTS idx_log_date ON daily_log(log_date);几个设计决定值得说一下。日期用TEXT而不是某种日期类型,是因为 SQLite 没有原生日期类型,ISO 字符串的字典序和时间的先后序完全一致,排序、范围查询都不会出问题,省心。shed_level允许为 NULL 是关键——它区分了“没洗头所以没观察”和“洗了头但确实没掉”,这个区别在统计时非常重要。
events我选择用逗号分隔的字符串而不是单独建关联表。这是个刻意的取舍:个人项目的数据量撑死几百行,查询复杂度不值那点规范化带来的麻烦,而字符串让我可以直接LIKE '%换洗发水%'一把梭。
3.2 记录入口:一个函数解决全部录入
录入这块我用的是“当天可反复修改”的 upsert 逻辑,因为现实中你经常是先填一半,晚上想起来再补,或者填错了要改。
import sqlite3 from datetime import date SHED_LEVELS = {"无": 0, "少量": 1, "中量": 2, "偏多": 3, "明显多": 4} def upsert_log(conn, log_date=None, washed=False, shed=None, pillow=None, scalp=None, sleep_hours=None, events=None, note=None): """当天记录写入或更新,同一天重复调用会覆盖而不是报错。""" log_date = log_date or date.today().isoformat() conn.execute(""" INSERT INTO daily_log (log_date, washed, shed_level, pillow_level, scalp_state, sleep_hours, events, note) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(log_date) DO UPDATE SET washed = excluded.washed, shed_level = excluded.shed_level, pillow_level = excluded.pillow_level, scalp_state = excluded.scalp_state, sleep_hours = excluded.sleep_hours, events = excluded.events, note = excluded.note """, ( log_date, 1 if washed else 0, SHED_LEVELS.get(shed) if washed else None, {"无": 0, "有": 1, "多": 2}.get(pillow), scalp, sleep_hours, events, note, )) conn.commit()这里的细节是shed_level在未洗头时强制写 NULL,哪怕是用户误填了也覆盖掉。加这一行判断能避免掉一大类数据污染——我自己就干过好几次,明明没洗头,手滑把档位填上了,事后统计时才发现那天被算进了样本。
调用起来就是一行:
conn = sqlite3.connect("hair_log.db") upsert_log(conn, washed=True, shed="中量", pillow="有", scalp="oil", sleep_hours=6.5, events="换洗发水", note="")3.3 照片归档:命名规范比文件夹结构更重要
照片我按“年月目录 + 日期分区序号”的方式组织:
photos/ ├── 2024-04/ │ ├── 20240428_front_01.jpg │ ├── 20240428_top_01.jpg │ └── 20240428_side_01.jpg └── 2024-05/ ├── 20240501_front_01.jpg └── ...为什么不用“第几天”命名?因为我试过,中间断档三天之后序号就全乱了,第 30 天其实已经是第 34 天,后面所有分析全歪。用绝对日期命名是唯一不会出错的方案,因为日期本身就是唯一且不会重复的。
归档我写了个小脚本,插上数据线把当天照片拖进一个临时目录,跑一下自动改名归位:
from pathlib import Path import shutil from datetime import date ZONE_MAP = {"front": "front", "top": "top", "side": "side"} def archive_day(src_dir: str, log_date: str, zones=("front", "top", "side")): src = Path(src_dir) month_dir = Path("photos") / log_date[:7] month_dir.mkdir(parents=True, exist_ok=True) files = sorted([p for p in src.iterdir() if p.suffix.lower() in (".jpg", ".jpeg")]) if len(files) < len(zones): print(f"警告:只找到 {len(files)} 张,预期 {len(zones)} 张,请核对") for seq, (f, zone) in enumerate(zip(files, zones), start=1): dst = month_dir / f"{log_date.replace('-', '')}_{zone}_{seq:02d}.jpg" shutil.copy2(f, dst) print(f"{f.name} -> {dst}")这个脚本里有个小设计:数量不足时只警告不中断。因为现实里经常某天少拍一张,如果直接报错退出,你会被迫手动处理,久而久之就懒得弄了。容错比严格更有利于长期坚持。
3.4 趋势可视化:离散指标别当连续值算
可视化这块我踩过一个不大不小的坑。掉发档位是 0 到 4 的序数变量,我最初直接求周均值画折线,结果图上出现了 2.37 这种数,看着很精确,其实毫无意义——档位之间的间距本来就不等,均值会误导人。
改成滚动中位数之后,曲线才变得能读。中位数对极端值免疫,不会被某一天的异常值带偏。
import pandas as pd import matplotlib.pyplot as plt def wash_day_trend(db_path="hair_log.db", window=4): conn = sqlite3.connect(db_path) df = pd.read_sql("SELECT * FROM daily_log ORDER BY log_date", conn) df["log_date"] = pd.to_datetime(df["log_date"]) # 只在洗头日上做趋势,避免干湿条件混杂 wash = df[df["washed"] == 1].copy() wash["shed_med"] = wash["shed_level"].rolling(window, min_periods=2).median() fig, ax = plt.subplots(figsize=(10, 4.5)) ax.scatter(wash["log_date"], wash["shed_level"], s=18, alpha=0.45, label="单日档位") ax.plot(wash["log_date"], wash["shed_med"], linewidth=2, label=f"{window} 次滚动中位数") ax.set_yticks([0, 1, 2, 3, 4]) ax.set_yticklabels(["无", "少量", "中量", "偏多", "明显多"]) ax.set_title("洗头日掉发档位趋势") ax.legend() ax.grid(alpha=0.25) plt.tight_layout() plt.savefig("trend.png", dpi=140)window=4这个参数是我试出来的。按隔天洗的频率,4 次洗头大约覆盖 8 到 10 天,既能把单日噪声压下去,又不至于平滑到看不出变化。窗口设成 2 太抖,设成 8 又迟钝得像个滞后指标,四到六之间是比较舒服的区间。
除了折线,我还做了一张“分区照片时间轴”——把每个分区的照片按月份排成一行缩略图。这个东西的价值在于它是唯一能看结构性变化的手段。掉发量反映的是“最近掉了多少”,而照片反映的是“整体密度变没变”,两者不是一回事,缺一不可。
4. 数据分析:怎么判断“有效”还是“没变化”
4.1 单一指标一定会骗你
我最开始只看洗头日掉发量,结果被它骗了至少两次。一次是换了洗发水之后掉发档位明显下降,我高兴了两周,后来发现那段时间刚好把洗头频率从每天改成了隔天——洗得少了,单次掉的当然显得多,反过来也成立。另一次是入秋之后掉发量上升,我以为是情况恶化,回看往年记录才发现每年这个时间段都有类似波动。
后来我固定用四个指标交叉判断:
| 指标 | 观察窗口 | 反映什么 | 权重 |
|---|---|---|---|
| 洗头日掉发档位中位数 | 4 周滚动 | 短期脱落强度 | 中 |
| 枕头掉发频率 | 4 周统计 | 日常脱落基线 | 低 |
| 同分区照片密度对比 | 月度 | 结构性变化 | 高 |
| 主观整体感受 | 月度 | 兜底校准 | 低 |
权重不是拍脑袋定的。照片之所以权重最高,是因为它不受洗头频率、季节波动这类短期因素影响,反映的是累积结果;而洗头日掉发量虽然灵敏,但干扰变量太多,只适合当“预警”用,不适合当“结论”用。
4.2 用基线期和干预期做对比
判断某个变化有没有意义,关键是别拿今天和昨天比,要拿一段时间和另一段时间比。我自己的做法是设一个基线期和一个干预期,各取至少三周,然后比较中位数。
import numpy as np def compare_periods(df, base, test): """base / test 是 (start, end) 日期字符串元组,返回档位中位数变化。""" def med(rng): s, e = rng sub = df[(df["log_date"] >= s) & (df["log_date"] <= e) & (df["washed"] == 1)] return sub["shed_level"].median(), len(sub) b_med, b_n = med(base) t_med, t_n = med(test) if b_n < 4 or t_n < 4: return {"warning": "样本太少,结论不可靠", "base_n": b_n, "test_n": t_n} return { "base_median": b_med, "test_median": t_med, "delta": t_med - b_med, "base_n": b_n, "test_n": t_n, }用中位数而不是均值,是因为档位分布经常是偏的,少数几天“明显多”能把均值拉高一大截,中位数稳得多。另外这个函数里我加了样本量检查,少于 4 个洗头日就直接返回警告——这是被坑出来的经验,有一回我拿两周共 3 个样本做对比,得出的结论后来被四周数据完全推翻。
判断标准我写成了下面这张表,贴在项目 README 里提醒自己别自欺欺人:
| 中位数变化 | 持续时间 | 我的判断 | 下一步动作 |
|---|---|---|---|
| 下降 ≥ 1 档 | 连续 ≥ 3 周 | 可能有效 | 保持现状,继续观察一个月 |
| 下降但不足 1 档 | 连续 ≥ 4 周 | 微弱信号 | 不换方案,延长观察 |
| 上下波动无方向 | 任意 | 无结论 | 检查混杂变量 |
| 上升 ≥ 1 档 | 连续 ≥ 2 周 | 需要排查 | 回看事件字段找原因 |
4.3 一次只改一个变量
这条是我从别的地方移植过来的思路,但用在这个项目上特别合适:每次只改一个变量,并且给它足够长的观察期。具体做法是记录一个events标签,标注从哪天开始做了什么改变,然后只看这个标签之后的窗口。
我试过同时换洗发水、调整洗头频率、换枕套材质,结果两个月后掉发确实变少了,但我完全不知道是哪一项起的作用。后来老老实实重来,一次只动一个,每项观察三周。虽然慢,但结论是可复现的,这比“感觉有效”值钱得多。
注意:所谓“观察三周”不是随便定的。太短了压不住噪声,太长了又会被其他环境的自然变化干扰。三到四周大概是个平衡点,具体到你自己,可以根据记录的波动幅度调整——波动大的就拉长,波动小的可以缩短。
5. 常见问题与排查技巧实录
5.1 记录断档了怎么办
断档是这个项目最大的敌人,几乎每个长期记录的人都会遇到。我经历过两次超过十天的断档,第一次试图回忆补填,结果填进去的数据八成是编的,反而污染了整个数据集。第二次我学乖了,宁可留空白也不补编。
现在的补救策略是三条:一是断档期间的数据在分析时整段排除,不做插值不做猜测;二是在表里加一个gap_flag字段,明确标出哪段是空的,避免自己以后误读;三是把“一周至少四天”设成最低可接受标准,低于这个就算本周无效,不强行凑数。
真正管用的其实是降低单日记录成本。我把记录页做成了一个本地网页,打开就能填,提交后存 localStorage,不用登录不用联网。降低摩擦比提高意志力有效得多。
5.2 那些看起来“变好了”的假象
这一类假象我整理成了一张速查表,每次看到明显好转,先过一遍这张表再高兴。
| 现象 | 可能的假象来源 | 怎么验证 | 怎么处理 |
|---|---|---|---|
| 掉发档位突然下降 | 洗头频率变低了 | 查washed频率变化 | 按洗头日分组重算 |
| 照片看着发量变多 | 光线更亮 / 头发更干 | 对比同分区同灯光的旧图 | 只用固定机位的图 |
| 换了产品后立刻见效 | 心理预期 + 短期波动 | 看四周滚动值是否持续 | 至少观察三周再下结论 |
| 某周数据特别好 | 那周只记了两天 | 检查样本量 | 样本不足直接作废 |
| 整体趋势向下 | 季节因素叠加 | 对比去年同期 | 拉长到季度尺度看 |
这张表里最坑我的是第二条。有一阵我换了浴室的灯泡,亮度提升了一截,那批照片看起来头发浓密了不少,我当时还真信了,直到把新旧照片放在一起叠图比对才发现是光线问题。照片类数据的最大陷阱就是视觉系统太容易被环境变量带偏。
5.3 高频问题速查
下面这几个是我自己在群里、评论区被问得最多的问题,一并集中答一下。
| 问题 | 我的处理方式 | 背后的理由 |
|---|---|---|
| 每天都要拍吗 | 只在洗头日拍 | 干湿条件统一才可比,频率低才坚持得久 |
| 掉发要不要数根数 | 不数,只记五档 | 数数误差大且极易劝退 |
| 用手机自带相册行不行 | 不行,一定要独立归档 | 相册会被自动压缩、自动分类,原始数据会丢 |
| 记录多久才能看出趋势 | 至少四周,建议八周 | 短于四周的波动基本是噪声 |
| 数据要不要备份 | 每周一次,db 文件和照片目录一起备 | 这类数据丢了没法重建 |
| 中途换手机怎么办 | 换之前把全部原始照片导出一份 | 新机型镜头参数不同,会有系统性偏差 |
最后一条尤其值得说。我换过一次手机,新机型的主摄焦距、色彩倾向都不一样,那前后两个月的照片放在一起比,密度看着差了一大截,其实只是镜头差异。后来我养成了一个习惯:换设备时留一个“过渡周”,新旧手机各拍一份,作为两套数据的校准锚点。
6. 我自己的几条使用体会
这东西跑了小半年,最大的收获其实不在数据本身,而在于它把一个模糊的、持续消耗注意力的焦虑,变成了一个每周花十分钟就能处理完的例行事项。焦虑最耗人的地方不是问题本身,是它没有边界——你不知道该想多久,所以一直在想。有了固定的记录和固定的复盘周期,这件事就被框住了。
说几个具体的心得。第一,别把记录当成诊断。它能告诉你趋势,但趋势里的因果得靠你自己去验证,任何涉及身体状况的异常,该找专业人士还是得找。第二,判断标准要提前写死,别等数据出来了再定“什么算有效”,那样你一定会不自觉地往自己想要的方向解释。第三,定期清理无效字段,我每两个月会回头看一遍哪些字段从来没被用于分析,然后果断删掉,记录表越轻越好活。
如果后面还想继续扩展,我大概会加两个方向:一是把分区照片做成可叠加的半透明对比图,这样密度的细微变化会更直观;二是把睡眠、洗头频率这些变量做成一个简单的相关性矩阵,虽然样本量注定不足以支撑严格的统计结论,但至少能提示“这两个东西可能有关”,给下一步的对照实验提供方向。这两块我还在琢磨,等内容攒够了再写一篇。