Python 推导式与生成器表达式
列表/集合/字典推导与生成器表达式用声明式构造数据;注意作用域、可读性与惰性求值边界。
#concept
#growing
#dev
#python
#python
[!info] related notes
Python 推导式与生成器表达式
这个概念为什么出现
从一批订单过滤出待发货 ID、从日志抽状态码——用 for + append 冗长。推导式把“映射/过滤”压缩为表达式;生成器表达式则惰性产出,避免一次性物化大列表。
[!abstract] 一句话理解 推导式声明式构建 list/set/dict;生成器表达式用圆括号惰性产出元素,可迭代一次。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:订单中心筛选可发货单并统计渠道
# orders_comprehension.py
# 业务意图:过滤 paid 订单、映射发货任务、统计渠道集合。
# 教学点:
# - list/set/dict 推导;
# - 生成器表达式节省中间列表;
# - 可读性:复杂逻辑不要硬塞一行。
def main() -> None:
orders = [
{"id": "O1", "status": "paid", "channel": "app"},
{"id": "O2", "status": "cancel", "channel": "web"},
{"id": "O3", "status": "paid", "channel": "app"},
]
ship_ids = [o["id"] for o in orders if o["status"] == "paid"]
channels = {o["channel"] for o in orders}
status_index = {o["id"]: o["status"] for o in orders}
total_paid = sum(1 for o in orders if o["status"] == "paid") # 生成器表达式
print("ship:", ship_ids)
print("channels:", channels)
print("index:", status_index)
print("paid count:", total_paid)
if __name__ == "__main__":
main()
建议运行:
python orders_comprehension.py
期望输出:
ship: ['O1', 'O3']
channels: {'app', 'web'}
index: {'O1': 'paid', 'O2': 'cancel', 'O3': 'paid'}
paid count: 2
(channels 集合展示顺序可能不同。)
结合场景再看三个关注点
- 过滤 + 映射是推导式主场。
sum(1 for ...)不必先建 list。- 嵌套三层推导通常应拆函数。
核心概念与准确模型
[expr for x in xs if cond]
{expr for x in xs}
{k: v for x in xs}
(expr for x in xs) # generator
- Python 3 的推导式循环目标不会泄漏到外围作用域;这不表示其中所有赋值都局部化,:= 通常绑定到包含它的作用域,并有使用限制。
- 可嵌套 for,但要克制
边界情况与反直觉行为
- 生成器耗尽后为空,不能当列表反复遍历除非物化。
- 字典推导式产生重复键时保留最后的值;集合推导去重且无插入顺序保证,不应将两者当作无损列表转换。
- 生成器表达式最左侧 for 的 iterable 表达式和迭代器创建立即发生;其余取值、过滤和元素表达式通常等消费时才执行,因此异常既可能在构造时也可能在迭代时出现。
常见误区
[!warning] 常见误区:所有循环都改成推导 错误理解:推导一定更 Pythonic。
正确模型:有副作用(写库、打印)的流程用 for;纯映射过滤用推导。
工程实践
- 超过两层条件拆函数命名。
- 大数据管线优先生成器/迭代器链。
- 与
map/filter二选一,团队统一风格。
本节总结
推导式提升表达密度;生成器表达式控制内存。可读性永远优先于“一行装下宇宙”。
自测题
- 列表推导与生成器表达式在内存上的关键差别?
- 何时不该用推导?
参考答案
- 列表立即物化全部元素;生成器按需产出但会保留迭代状态和引用,输入已物化或后续再 list(…) 时仍可能占用大量内存。
- 需要多语句、复杂分支或明显副作用时。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Data Structures – List Comprehensions | 教程 | 推导式 |
| Generator expressions | 规范 | 语法 |