一、前言
在 Python 中,如果你想创建一个新列表,最"新手"的写法可能是:
python
squares = []
for x in range(10):
squares.append(x ** 2)
但 Python 老手会这样写:
python
squares = [x ** 2 for x in range(10)]
这就是------列表推导式(List Comprehension)。
它不仅是语法糖,更是 Python 哲学"简洁优于复杂"的完美体现。
但你真的会用吗?
- 如何在推导式中加
if条件? - 能否实现双重循环(如矩阵展平)?
- 推导式和
map()/filter()谁更快? - 什么时候不该用推导式?
本文将带你: ✅ 掌握列表推导式的 5 种核心写法
✅ 学会嵌套、条件、多表达式等高级技巧
✅ 理解其性能优势与内存效率
✅ 避开可读性差、逻辑混乱等陷阱
✅ 写出既快又美的 Pythonic 代码
二、基础语法:从 for 到推导式
通用格式
python
[expression for item in iterable]
示例对比
| 传统写法 | 列表推导式 |
|---|---|
py<br>res = []<br>for i in range(5):<br> res.append(i*2) |
py<br>res = [i*2 for i in range(5)] |
结果:[0, 2, 4, 6, 8]
✅ 优势:代码行数减少 50%,意图更清晰。
三、带条件过滤:if 的妙用
1. 后置条件(最常用)
python
# 只保留偶数的平方
evens = [x ** 2 for x in range(10) if x % 2 == 0]
# 结果:[0, 4, 16, 36, 64]
2. 条件表达式(三元运算)
python
# 奇数变负,偶数不变
transformed = [x if x % 2 == 0 else -x for x in range(5)]
# 结果:[0, -1, 2, -3, 4]
🔍 注意区别:
if在末尾 → 过滤元素if-else在开头 → 转换值
四、嵌套循环:处理多维数据
1. 双重循环(展平二维列表)
python
matrix = [[1, 2, 3], [4, 5, 6]]
flattened = [num for row in matrix for num in row]
# 结果:[1, 2, 3, 4, 5, 6]
📌 执行顺序 :从左到右,外层在前,内层在后
等价于:
pythonfor row in matrix: for num in row: ...
2. 生成笛卡尔积
python
colors = ['red', 'blue']
sizes = ['S', 'M']
combinations = [f"{c}-{s}" for c in colors for s in sizes]
# 结果:['red-S', 'red-M', 'blue-S', 'blue-M']
五、高级技巧:不止于列表
技巧 1:结合函数调用
python
words = ['hello', 'WORLD']
lower_words = [w.lower() for w in words]
# ['hello', 'world']
技巧 2:处理字典或对象
python
students = [{'name': 'Alice', 'score': 90}, {'name': 'Bob', 'score': 85}]
names = [s['name'] for s in students if s['score'] > 85]
# ['Alice']
技巧 3:生成索引-值对(替代 enumerate)
python
data = ['a', 'b', 'c']
indexed = [(i, v) for i, v in enumerate(data)]
# [(0, 'a'), (1, 'b'), (2, 'c')]
六、性能对比:为什么推导式更快?
我们用 timeit 测试三种方式生成 [x**2 for x in range(10000)]:
| 方法 | 平均耗时(1000次) | 说明 |
|---|---|---|
for + append() |
~1.8 ms | 每次调用 append 有函数开销 |
map(lambda x: x**2, ...) |
~1.5 ms | C 层优化,但 lambda 有开销 |
| 列表推导式 | ~1.2 ms | 最快!底层用 C 实现,无函数调用 |
✅ 结论 :
列表推导式不仅更简洁,通常也更快!
💡 原因:CPython 对推导式做了专门优化,避免了方法查找和函数调用。
七、常见误区与避坑指南
❌ 误区 1:过度嵌套导致可读性差
python
# 难以理解!
result = [func(x, y, z) for x in A for y in B if cond(x) for z in C if cond2(z)]
✅ 建议:超过两层嵌套,或逻辑复杂时,改用普通 for 循环。
❌ 误区 2:在推导式中执行副作用操作
python
# 危险!不要这样做
[print(x) for x in range(5)] # 用列表推导式只是为了 print?
✅ 正确:副作用操作(如 print, write)应使用普通循环。
🌟 黄金法则 :
推导式用于"构建新数据",而非"执行动作"。
❌ 误区 3:误以为推导式节省内存
python
huge_list = [x for x in range(10**7)] # 仍会占用大量内存!
✅ 如果内存敏感,改用生成器表达式(小括号):
python
huge_gen = (x for x in range(10**7)) # 惰性求值,几乎不占内存
❌ 误区 4:变量泄漏(仅 Python <3.0)
⚠️ 在 Python 2 中,推导式的循环变量会泄漏到外层作用域。
但在 Python 3+ 中已修复!
python[x for x in range(3)] print(x) # NameError: name 'x' is not defined(Python 3 安全)
八、与其他推导式的对比
Python 还支持:
- 集合推导式 :
{x for x in ...} - 字典推导式 :
{k: v for k, v in ...} - 生成器表达式 :
(x for x in ...)
python
# 字典推导式:反转键值
original = {'a': 1, 'b': 2}
reversed_dict = {v: k for k, v in original.items()} # {1: 'a', 2: 'b'}
# 集合推导式:去重并转换
unique_squares = {x**2 for x in [1, 2, 2, 3]} # {1, 4, 9}
✅ 列表推导式是这类语法的"原型",掌握它就掌握了整个家族!
九、最佳实践总结
| 场景 | 推荐做法 |
|---|---|
| 简单映射/过滤 | 用列表推导式 |
| 多层嵌套(>2) | 改用普通循环 |
| 需要副作用 | 用 for 循环 |
| 内存敏感 | 用生成器表达式 (x for x in ...) |
| 构建字典/集合 | 用对应推导式 {} |
| 性能关键路径 | 优先推导式(比 map/filter 更快更清晰) |
🌈 Python 之禅提醒我们 :
"可读性很重要。"当推导式变得难以一眼看懂,就是该停手的时候。
十、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!