你有没有过这种经历:接手一个项目,打开代码一看,缩进七层、循环里套计数器、字典手工判空,功能都对,但读起来像在啃一行行汇编。语法没错,逻辑没错,可就是一股浓浓的「外语腔」——就像一个英语很好的人,说话却句句都是中式语序。
今天要深读的这场演讲,就是治这个病的。Raymond Hettinger 的《Transforming Code into Beautiful, Idiomatic Python》,2013年3月在 PyCon US(Santa Clara)上录制,由 PyCon 官方频道发布,是 Python 社区公认的「必看神课」之一,十多年过去仍在各类「Python开发者必看清单」里被反复推荐。Hettinger 是 Python 核心贡献者,itertools 模块作者、collections 模块(defaultdict、namedtuple 等)的主要作者,sorted() 的 key= 参数设计背后也有他的推动——换句话说,你现在每天用的不少「Python味」,就是这个人参与定义的。
在 AI 能一行行吐代码的今天,这场十二年前的演讲非但没过时,反而更值钱了:生成代码容易了,判断代码「地道不地道」成了人类工程师的稀缺能力。下面进入正题。
| 项目 | 内容 |
|---|---|
| 视频标题 | Transforming Code into Beautiful, Idiomatic Python |
| 频道 | PyCon US(官方频道) |
| 发布时间 | 2013年(PyCon US 大会演讲实录) |
| 时长 | 约49分钟 |
| 播放量 | 数百万级(平台实时数据以 YouTube 页面为准) |
| 核心主题 | 用 Python 惯用法重写「生硬代码」,让代码更快、更短、更可读 |
说明:本文基于视频内容与公开资料撰写,播放量等平台动态数据以 YouTube 实时页面为准。
很多人把这场演讲当成「语法技巧合集」,其实低估了它。Hettinger 开篇就把惯用法(idiom)定义为社区沉淀下来的最佳表达方式——不是某个天才的发明,而是成千上万程序员在真实项目里试错后收敛出的共识。他的口头禅全场回荡:"There must be a better way!"(一定有更好的写法)每当你写出生硬的代码时,先别急着往下敲,停一秒,想想社区是不是已经给出过更好的答案。
他还有一个非常动人的观点(视频原话大意):如果你是专家,请回头去改善集体的智慧——去 StackOverflow 回答问题、去改文档。他本人就是这么做的,他在 StackOverflow 上的 Python 回答至今仍是大量开发者的入门教材。
延伸分析:这其实是编程语言学习里最容易被忽略的一层。学语法是「把句子说对」,学惯用法是「说得像母语者」。母语者扫一眼代码就能闻出「外来者」的味道,而代码的地道程度,直接决定了团队 review 的速度、新人上手的成本、以及三年后你自己回读时的痛苦程度。惯用法不是风格偏好,是沟通成本问题。
演讲最出圈的部分,是他把最常见的 C 风格循环逐一「进化」。这是整场戏肉,值得完整梳理(示例为笔者依演讲要点整理):
# 生硬:把机器思维带进了高级语言
for i in range(len(names)):
print(names[i])
# 地道:直接表达「对每个名字做什么」
for name in names:
print(name)
在这个基线上,他连续展示了六种场景的惯用改写:需要下标时用 enumerate(names);同时遍历两个序列时用 zip(a, b);倒序遍历用 reversed(names),而不是手写 range(len(names)-1, -1, -1) 这种反人类的东西;有序遍历直接 sorted(names, key=...);去重遍历用 set(names)。
他的核心主张可以概括为一句话:循环应该表达「我要对什么做什么」,而不是「计数器怎么走」。for i in range(len(xs)): xs[i] 这种写法,本质上是把 C 语言的机器模型原封不动搬进了 Python——用他的话说,就是别在任何语言里写别的语言(大意转述)。
Hettinger 对字典的偏爱贯穿全场。他演示了两类最高频的场景。第一类是计数:
# 生硬:手工判空
counts = {}
for ch in "abracadabra":
if ch not in counts:
counts[ch] = 0
counts[ch] += 1
# 地道:get 一行搞定
counts = {}
for ch in "abracadabra":
counts[ch] = counts.get(ch, 0) + 1
第二类是分组——把元素按某个键归类到列表里。生硬写法要判断 key 是否存在再 append,地道写法是 defaultdict(list),一行解决。他还强烈推荐 namedtuple:与其让函数返回一个裸元组、调用方靠位置去猜第几个字段是什么,不如给每个字段起名字,代码自带文档。
延伸分析:这场演讲之后,社区沿着这个方向继续标准化——collections.Counter 把「计数惯用法」直接做成了类型,一行 Counter(s).most_common(3) 连排序都替你办了;后来的 dataclasses 和 typing.NamedTuple 则接棒了 namedtuple 的思想。你今天觉得「Python 写起来真顺手」的很多瞬间,都是这条「惯用法 → 标准库」流水线的产物:先在社区形成最佳实践,成熟了就沉淀进语言。
这场演讲另一个被严重低估的部分:很多性能优化根本不需要算法天赋,只需要选对数据结构。Hettinger 给了三组经典对照:
| 场景 | 慢的做法 | 惯用做法 | 差异本质 |
|---|---|---|---|
| 成员测试 | x in big_list |
x in big_set |
线性扫描 vs 哈希一步定位 |
| 左端弹出 | queue.pop(0) |
deque.popleft() |
全体搬家 vs 常数时间摘头 |
| 字符串累积 | s += part |
''.join(parts) |
反复整体拷贝 vs 一次成型 |
他现场展示的数据量级差异相当震撼:成员测试从「百万条逐个比对」变成「哈希表一次命中」,复杂度从 O(n) 掉到常数级。而且这些改写不牺牲可读性,反而更短。
延伸分析(视频外的背景补充):这些差异不是玄学,是 CPython 的内部实现决定的——list 是动态数组,中间插入或头部删除意味着后面所有元素整体移位;deque 则是分块双向链表,两端操作天然便宜。所以「选结构」本质是「理解结构背后的内存布局」。同样一行代码,复杂度天差地别,而性能税是在写下的那一刻就交完了的,不是运行时才浮现的。
Python 之禅(PEP 20)里有一条:Flat is better than nested(扁平优于嵌套)。Hettinger 把它落成了具体的手法。第一招是 guard clause(卫语句)提前返回:与其把主逻辑包在层层 if 里,不如先把不合法的情况一个个挡在门口,主逻辑零缩进平铺直叙。第二招是 Python 特有的 for-else:循环体后面跟一个 else,循环「没被 break 打断、自然跑完」时执行——写搜索类逻辑时,能优雅处理「没找到」的分支,不用引入 found 标志变量。
他还有一个全场反复强调的原则:one logical line of code——把「一个逻辑动作」写成一行。不是为了压行数炫技,而是因为当一行代码只表达一个完整意图时,大脑可以整行整块地读,像读句子一样;反过来,五行拆开的中间变量、或者七层嵌套的深渊,都强迫读者在脑内手动维护一个「状态栈」。
延伸分析:缩进深度其实可以直接当作复杂度的量化指标。嵌套每加深一层,读者要在脑内多压一层上下文,review 出错率随之上升。后来社区流行的「提前返回 + 小函数」重构法、甚至 CodeAesthetic 那支《Why You Shouldn't Nest Your Code》爆款视频,讲的都还是这件事——认知税是真实存在的,而且按嵌套层数复利计息。
Hettinger 专门讲了一类反直觉的优化:最快的代码,是不做不必要工作的代码。第一件武器是生成器表达式——(x*x for x in xs) 不会先把整份结果建成列表再喂给下游,而是流式吐出,处理超大文件或无限序列时内存占用完全不是一个量级。配套的 itertools 工具箱(islice、chain、groupby……)就是为「流式、惰性」组合而生——他本人正是这个模块的作者,现场他半开玩笑地提醒大家去读文档(大意)。
第二件武器是 functools.lru_cache:一个装饰器,让重复调用的函数自动走缓存。他演示了给递归函数加一行装饰器、性能从指数级掉到线性级的例子——一行代码,胜过手写一套缓存逻辑。
延伸分析:这两件事看似不相关,内核却是同一种品味——识别重复劳动,然后把它交出去:交给惰性求值(不提前干以后可能用不上的活),交给缓存(已经干过的活不再干第二遍)。这套思路放到系统设计层面就是流式计算和 memoization,放到个人工作流层面就是自动化脚本。品味是相通的。
资源管理部分,Hettinger 展示了 with 语句的正确打开方式。没有 with 的世界,打开文件要 try/finally 里手写 close(),用锁要先 acquire() 再记得 release()——每一处都依赖工程师「一定记得做」,而忘了的那次就是事故。有了 with:
with open('data.txt') as f:
process(f)
with lock: # 自动加锁、自动释放,想忘都忘不掉
update_shared_state()
无论中途 return、break 还是抛异常,清理动作必然执行。他强调这类惯用法的价值在于:把正确性从「纪律」问题变成「结构」问题——不靠人自觉,靠语言机制兜底。
延伸分析:这是整场演讲里最具工程哲学味道的一点。好的语言特性不是让正确的代码写得更快,而是让错误根本写不出来。上下文管理器、后来的 async with、contextlib 工具箱,都在扩展这个思路。做工程的人可以记住这个判断标准:如果你的流程靠「大家都小心点」来保证,那它迟早出事;把它做成结构,才是真的解决。
最后说说我的延伸判断。2013 年的代码示例,有些 API 已经演进(dict.iteritems 早成了 items),但这场演讲的生命力反而越来越强,原因有三层。
第一,它教的是表达方式,不是版本特性。enumerate 和 zip 会换名字,但「用数据结构表达意图、用惯用法降低沟通成本」的思想永不退役。Python 后来的 match-case、dataclass、类型标注,全都可以用演讲里的同一套品味去审视。
第二,AI 编程时代,审美的稀缺性上升了。2026 年的今天,让模型生成一段「能跑的代码」是几秒钟的事;但判断这段代码是地道的 Python 还是「用 Python 语法的 C」,需要受过训练的眼睛。这场演讲几乎可以直接当成 code review 的标尺:range(len())、手工计数器、pop(0)、七层缩进、手写缓存——看到就触发改造。换句话说,它培养的正是这个时代最值钱的能力:鉴别与品味。
第三,它演示了一个专家如何反哺社区。Hettinger 把多年功力压缩成五十分钟,配上文档和 StackOverflow 回答,让整个生态的水位上升。技术演讲浩如烟海,能被一代代新人反复挖出来重看的极少——因为它们的作者卖的不是信息,是经过时间检验的判断力。
flowchart TD
A["Python惯用法:地道的代码"] --> B["遍历进化"]
A --> C["字典惯用法"]
A --> D["数据结构选型"]
A --> E["控制流扁平化"]
A --> F["惰性与缓存"]
A --> G["资源管理"]
B --> B1["直接迭代对象"]
B --> B2["enumerate 与 zip"]
B --> B3["sorted 与 reversed"]
C --> C1["defaultdict 计数与分组"]
C --> C2["namedtuple 自文档化"]
D --> D1["set 成员测试常数级"]
D --> D2["deque 左端操作常数级"]
D --> D3["join 一次成型拼接"]
E --> E1["卫语句提前返回"]
E --> E2["for else 搜索模式"]
F --> F1["生成器表达式流式处理"]
F --> F2["itertools 惰性工具箱"]
F --> F3["lru_cache 自动缓存"]
G --> G1["with 上下文管理器"]
G --> G2["锁与事务的自动清理"]
看完这场演讲,别只收藏。给你一套可以直接落地的行动方案。
第一步:给团队立一条 review 红线。 把这几条写进 code review 清单:出现 range(len(xs)) → 改直接迭代或 enumerate;手工判空计数 → defaultdict 或 Counter;pop(0) → deque;循环里 += 拼字符串 → join;列表大成员测试 → set。每条都是机械替换,风险低、收益立竿见影,特别适合作为团队「Python 味」改造的起点。
第二步:重构按三段走。 先跑测试锁住行为(没有测试先补冒烟用例);再做机械替换,一次只改一类惯用法,diff 干净到 reviewer 三十秒能看完;最后对涉及 set 化、缓存、生成器的改动跑一次基准测试——绝大多数情况是白拿的性能,但缓存要留意失效策略,别把正确性优化没了。
第三步:把品味喂给 AI。 现在很多人的日常是让 AI 写代码。做法很简单:把 PEP 20 之禅和你的惯用法清单写进项目规范或 prompt 模板,明确要求「用惯用法、早返回、扁平化、标准库优先」。同一份需求,产出质量差距肉眼可见。AI 降低了写代码的门槛,也放大了「会不会验收」的差距——而这场演讲就是最好的验收教材。
第四步:迁移这个学习方法。 换任何一门新语言时,别先背语法,先搜「language idioms」和官方风格指南(Python 是 PEP 8,Go 是 Effective Go),把社区的「母语口音」先装进脑子。写对是及格线,写得地道才是专业。
import this 即可阅读。这门课真正教你的不是几个语法技巧,而是一种肌肉记忆:每写下一行生硬代码时,先停一秒问自己——There must be a better way。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
