欢迎光临
我们一直在努力

《Effective Python》读书笔记05: 推导与生成

作者: andylin02
学习章节: 第4章 – 推导与生成
关键词: 列表推导, 生成器表达式, yield from, send, throw, itertools, 赋值表达式, 内存效率


第4章思维导图:10条建议全景

#mermaid-svg-atCPPBYLPSMzTLS2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-atCPPBYLPSMzTLS2 .error-icon{fill:#552222;}#mermaid-svg-atCPPBYLPSMzTLS2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-atCPPBYLPSMzTLS2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-atCPPBYLPSMzTLS2 .marker.cross{stroke:#333333;}#mermaid-svg-atCPPBYLPSMzTLS2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-atCPPBYLPSMzTLS2 p{margin:0;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge{stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 text{fill:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon–1{font-size:40px;color:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge–1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth–1{stroke-width:17;}#mermaid-svg-atCPPBYLPSMzTLS2 .section–1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-0{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-0{stroke-width:14;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-1{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-1{stroke-width:11;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 text{fill:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-2{stroke-width:8;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-3{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-3{stroke-width:5;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-4{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-4{stroke-width:2;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-5{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-5{stroke-width:-1;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-6{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-6{stroke-width:-4;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-7{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-7{stroke-width:-7;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-8{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-8{stroke-width:-10;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-9{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-9{stroke-width:-13;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 polygon,#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 text{fill:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .node-icon-10{font-size:40px;color:black;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .edge-depth-10{stroke-width:-16;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled circle,#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:lightgray;}#mermaid-svg-atCPPBYLPSMzTLS2 .disabled text{fill:#efefef;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-root rect,#mermaid-svg-atCPPBYLPSMzTLS2 .section-root path,#mermaid-svg-atCPPBYLPSMzTLS2 .section-root circle,#mermaid-svg-atCPPBYLPSMzTLS2 .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-atCPPBYLPSMzTLS2 .section-root text{fill:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-root span{color:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .section-2 span{color:#ffffff;}#mermaid-svg-atCPPBYLPSMzTLS2 .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-atCPPBYLPSMzTLS2 .edge{fill:none;}#mermaid-svg-atCPPBYLPSMzTLS2 .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-atCPPBYLPSMzTLS2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

第4章 推导与生成 10条建议

推导式优化

第27条: 用推导取代map/filter

第28条: 推导中子表达式≤2个

第29条: 赋值表达式消除重复

生成器

第30条: 用生成器代替返回列表

第31条: 警惕迭代参数多次使用

第32条: 大数据用生成器表达式

第33条: yield from组合生成器

慎用特性

第34条: 不要用send注入数据

第35条: 不要用throw改变状态

迭代工具箱

第36条: itertools拼合迭代器


第4章详细笔记:逐条精讲与源代码

本章聚焦 Python 最具函数式风格的两大特性:推导式 与 生成器。掌握它们,你将能以极低的内存开销写出高度表达力的数据处理代码。

第27条:用列表推导取代 map 和 filter

核心:列表推导将“映射/过滤”逻辑融合进一个清晰表达式中,可读性优于 map/filter 的组合。

# ❌ 需要嵌套map/filter,可读性差
a = [1, 2, 3, 4, 5, 6]
result = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, a)))

# ✅ 列表推导一目了然
result = [x**2 for x in a if x % 2 == 0]
print(result) # [4, 16, 36]

# 字典推导与集合推导同样简洁
pairs = [('a', 1), ('b', 2)]
d = {k: v for k, v in pairs} # {'a':1, 'b':2}
s = {v for k, v in pairs} # {1,2}

关键收获:推导式是声明式的,直接表达“要什么”,而非“如何做”。


第28条:避免在推导式中使用超过两个控制子表达式

核心:推导式可以嵌套循环和多个 if,但超过两个子句(例如双层循环+两个条件)会急剧降低可读性,此时应回归传统 for 循环或辅助函数。

# ❌ 三层嵌套+条件,难以理解
matrix = [[[1,2],[3,4]],[[5,6],[7,8]]]
flat = [x for sub in matrix for row in sub for x in row if x > 3]

# ✅ 拆分为清晰的循环或辅助函数
def flatten_and_filter(matrix):
for sub in matrix:
for row in sub:
for x in row:
if x > 3:
yield x
flat = list(flatten_and_filter(matrix))

规则:推导式保持 不超过两个 for/if 组合。


第29条:用赋值表达式消除推导中的重复计算

核心:当推导中某个值需要多次使用,比如在 if 和输出中都用到,使用海象运算符 := 可以避免重复调用函数或重复计算。

import math

# ❌ 没有海象时,expensive_func 被调用了两次
data = [4, 9, 16]
result = [f(x) for x in data if f(x) > 0] # f(x) 重复调用

# ✅ 海象运算符计算一次,赋值并判断
result = [y for x in data if (y := f(x)) > 0]

# 实际例子:过滤平方根大于2的数
nums = [4, 9, 16, 25]
filtered = [sqrt for n in nums if (sqrt := math.sqrt(n)) > 4]
print(filtered) # [5.0, 5.0]?等等 math.sqrt(25)=5

关键收获::= 在推导中杜绝重复计算,提升性能与可读性。


第30条:考虑用生成器代替返回列表

核心:函数返回 list 会一次性将所有结果载入内存。改为返回生成器,可逐步产生结果,对大规模数据极其友好。

# ❌ 返回列表,大数据可能撑爆内存
def index_words(text):
result = []
if text:
result.append(0)
for index, letter in enumerate(text):
if letter == ' ':
result.append(index + 1)
return result

# ✅ 用 yield 生成结果,内存恒定
def index_words_iter(text):
if text:
yield 0
for index, letter in enumerate(text):
if letter == ' ':
yield index + 1

text = "Effective Python is great"
print(list(index_words_iter(text))) # [0, 9, 16, 19]

关键收获:生成器是流式处理的基石,避免 MemoryError。


第31条:当心迭代器参数的多次遍历

核心:生成器(或迭代器)只能遍历一次。若函数接受迭代器参数并需多次使用,需显式转为列表,或要求调用者传入可重复迭代的容器(如列表),并做好防御。

# ❌ 危险:迭代器只能玩一次
def normalize(numbers):
total = sum(numbers) # 第一次迭代
result = []
for value in numbers: # 第二次迭代时 numbers 已耗尽!
percent = 100 * value / total
result.append(percent)
return result

nums = iter([5, 10, 15])
# print(normalize(nums)) # 空结果或错误

# ✅ 解决方案1:在函数内拷贝为列表
def normalize_safe(numbers):
numbers = list(numbers) # 如果不是list,转为list
total = sum(numbers)
return [100 * v / total for v in numbers]

print(normalize_safe([5,10,15]))

关键收获:处理迭代器参数时,要么一次性消费,要么显式实体化。


第32条:对于大数据量的推导,考虑用生成器表达式

核心:列表推导用方括号 [] 生成列表;生成器表达式用圆括号 (),惰性产生值,内存效率极高。当列表推导结果只是作为另一个函数的输入时,直接用生成器表达式可以省掉中间列表。

# 场景:处理大文件,计算每行长度之和
# ❌ 列表推导先创建了巨大临时列表
with open('huge_file.txt') as f:
total = sum([len(line) for line in f])

# ✅ 生成器表达式直接传给 sum,无临时列表
with open('huge_file.txt') as f:
total = sum(len(line) for line in f)

语法注意:若生成器表达式是函数的唯一参数,可省略双括号。


第33条:用 yield from 组合多个生成器

核心:当一个生成器需要产出另一个生成器的所有值时,使用 yield from 取代手动循环 yield,它更简洁且能自动处理 send/throw/close 等高级协议。

# ❌ 手动迭代子生成器
def chain_generators(*args):
for gen in args:
for value in gen:
yield value

# ✅ yield from 扁平化
def chain_generators_yf(*args):
for gen in args:
yield from gen

def gen1():
yield 1; yield 2
def gen2():
yield 3; yield 4

print(list(chain_generators_yf(gen1(), gen2()))) # [1,2,3,4]

多级流水线:yield from 是构建生成器流水线的黏合剂。


第34条:不要用 send 向生成器注入数据

核心:生成器的 send(value) 方法注入值会破坏生成器的纯粹性,使其行为依赖外部状态,难以理解、测试和维护。应优先使用简单迭代或将状态封装在类中。

# ❌ send 让生成器变得诡异
def adder():
total = 0
while True:
x = yield
if x is None:
break
total += x
return total

gen = adder()
next(gen) # 必须先启动
gen.send(1)
gen.send(2)
try:
gen.send(None)
except StopIteration as e:
print(e.value) # 3
# 难以调试!

# ✅ 用简单的函数或类
def simple_adder(values):
return sum(values)

关键收获:远离 send,保持生成器为简单的数据流生产者。


第35条:不要用 throw 向生成器注入异常

核心:generator.throw(exc) 在生成器内部抛异常会制造隐式的控制流,让代码晦涩且易错。若需处理异常,应在生成器外部显式处理,或通过正常值传递。

# ❌ 用 throw 结束生成器,极不推荐
def my_gen():
try:
yield 1
yield 2
except GeneratorExit:
print("清理")

g = my_gen()
print(next(g))
g.throw(GeneratorExit) # 无法预测行为

# ✅ 在循环中自然结束,或通过 close
g = my_gen()
print(next(g))
g.close()

最佳实践:throw 几乎只应该由 yield from 内部使用,普通开发者不要碰。


第36条:考虑用 itertools 来拼合迭代器与生成器

核心:itertools 模块提供了大量构建迭代器流水线的积木,如 chain、islice、takewhile、dropwhile、groupby、tee 等,可极大简化生成器组合逻辑。

import itertools

# 场景:交错迭代三个列表
list1 = [1,2,3]
list2 = ['a','b','c']
list3 = [True, False]
chained = itertools.chain(list1, list2, list3)
print(list(chained)) # [1,2,3,'a','b','c',True,False]

# 分组数据
data = [('A', 1), ('A', 2), ('B', 3), ('B', 4)]
for key, group in itertools.groupby(data, key=lambda x: x[0]):
print(key, list(group))
# A [('A',1),('A',2)]
# B [('B',3),('B',4)]

常用武器:

  • itertools.islice(iter, stop) 惰性切片
  • itertools.takewhile(pred, iter) 满足条件就取
  • itertools.dropwhile(pred, iter) 跳过直到条件为假
  • itertools.product 笛卡尔积

🔄 派生器→生成器选择决策流程

#mermaid-svg-d9MirCeHM0CNxibj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-d9MirCeHM0CNxibj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-d9MirCeHM0CNxibj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-d9MirCeHM0CNxibj .error-icon{fill:#552222;}#mermaid-svg-d9MirCeHM0CNxibj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-d9MirCeHM0CNxibj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-d9MirCeHM0CNxibj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-d9MirCeHM0CNxibj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-d9MirCeHM0CNxibj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-d9MirCeHM0CNxibj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-d9MirCeHM0CNxibj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-d9MirCeHM0CNxibj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-d9MirCeHM0CNxibj .marker.cross{stroke:#333333;}#mermaid-svg-d9MirCeHM0CNxibj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-d9MirCeHM0CNxibj p{margin:0;}#mermaid-svg-d9MirCeHM0CNxibj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-d9MirCeHM0CNxibj .cluster-label text{fill:#333;}#mermaid-svg-d9MirCeHM0CNxibj .cluster-label span{color:#333;}#mermaid-svg-d9MirCeHM0CNxibj .cluster-label span p{background-color:transparent;}#mermaid-svg-d9MirCeHM0CNxibj .label text,#mermaid-svg-d9MirCeHM0CNxibj span{fill:#333;color:#333;}#mermaid-svg-d9MirCeHM0CNxibj .node rect,#mermaid-svg-d9MirCeHM0CNxibj .node circle,#mermaid-svg-d9MirCeHM0CNxibj .node ellipse,#mermaid-svg-d9MirCeHM0CNxibj .node polygon,#mermaid-svg-d9MirCeHM0CNxibj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-d9MirCeHM0CNxibj .rough-node .label text,#mermaid-svg-d9MirCeHM0CNxibj .node .label text,#mermaid-svg-d9MirCeHM0CNxibj .image-shape .label,#mermaid-svg-d9MirCeHM0CNxibj .icon-shape .label{text-anchor:middle;}#mermaid-svg-d9MirCeHM0CNxibj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-d9MirCeHM0CNxibj .rough-node .label,#mermaid-svg-d9MirCeHM0CNxibj .node .label,#mermaid-svg-d9MirCeHM0CNxibj .image-shape .label,#mermaid-svg-d9MirCeHM0CNxibj .icon-shape .label{text-align:center;}#mermaid-svg-d9MirCeHM0CNxibj .node.clickable{cursor:pointer;}#mermaid-svg-d9MirCeHM0CNxibj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-d9MirCeHM0CNxibj .arrowheadPath{fill:#333333;}#mermaid-svg-d9MirCeHM0CNxibj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-d9MirCeHM0CNxibj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-d9MirCeHM0CNxibj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-d9MirCeHM0CNxibj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-d9MirCeHM0CNxibj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-d9MirCeHM0CNxibj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-d9MirCeHM0CNxibj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-d9MirCeHM0CNxibj .cluster text{fill:#333;}#mermaid-svg-d9MirCeHM0CNxibj .cluster span{color:#333;}#mermaid-svg-d9MirCeHM0CNxibj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-d9MirCeHM0CNxibj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-d9MirCeHM0CNxibj rect.text{fill:none;stroke-width:0;}#mermaid-svg-d9MirCeHM0CNxibj .icon-shape,#mermaid-svg-d9MirCeHM0CNxibj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-d9MirCeHM0CNxibj .icon-shape p,#mermaid-svg-d9MirCeHM0CNxibj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-d9MirCeHM0CNxibj .icon-shape .label rect,#mermaid-svg-d9MirCeHM0CNxibj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-d9MirCeHM0CNxibj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-d9MirCeHM0CNxibj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-d9MirCeHM0CNxibj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

小/已知

大/未知

需要处理序列数据

数据量大小?

用列表推导或返回列表

是否需要多次遍历?

转为列表或要求调用者传入序列

使用生成器表达式或生成器函数

用yield from组合多个生成器

推导中是否有重复计算?

用赋值表达式消除重复

保持简洁,控制子表达式数量

善用itertools高效拼合


🎯 第4章总结:推导与生成的黄金法则

  • 推导式是映射与过滤的声明式武器,但保持简单(≤2子句),并用赋值表达式消除重复计算。
  • 生成器是内存效率之王:用 yield 代替返回列表,用生成器表达式代替大列表推导,用 yield from 串联生成器。
  • 躲开陷阱:不要依赖迭代器的多次遍历;绝对避免 send/throw,它们让生成器行为难以预测。
  • 善用 itertools:它是构造高效迭代流水线的标准库,生产力倍增器。
  • 掌握本章,你将能写出内存占用极低、可扩展性强、且如数据流般清晰的数据处理代码。


    下一章预告:第5章 – 类与接口

    理解了如何优雅地处理数据流之后,我们将进入 面向对象设计 的核心——类与接口。

    你将学到:

    • 为何 组合优于继承,以及如何实现
    • 怎样让接口接受函数而非类的实例,获得极度灵活性
    • 多态的高级实现:@classmethod、super() 与 Mixin 的正确用法
    • 属性访问控制:为何应优先使用公有属性,而非私有属性

    第5章将革新你设计 Python 类的方式!


    本文为个人学习笔记,仅用于知识分享。如有错误,欢迎指正。
    👍🏻 点赞 + 收藏 + 分享,让更多开发者看到这篇深度解析!❤️ 如果觉得有用,请给个赞支持一下作者!

    赞(0)
    未经允许不得转载:171主机测评 » 《Effective Python》读书笔记05: 推导与生成
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址