Python列表推导式

一、前言

在 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>&nbsp;&nbsp;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]

📌 执行顺序 :从左到右,外层在前,内层在后

等价于:

python 复制代码
for 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 之禅提醒我们
"可读性很重要。"

当推导式变得难以一眼看懂,就是该停手的时候。


十、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
消失的旧时光-194310 分钟前
C++ 多态核心三件套:虚函数、纯虚函数、虚析构函数(面试 + 工程完全指南)
开发语言·c++·面试·虚函数·纯虚函数·虚析构函数
Sakuraba Ema23 分钟前
从零理解 MoE(Mixture of Experts)混合专家:原理、数学、稀疏性、专家数量影响与手写 PyTorch 实现
人工智能·pytorch·python·深度学习·数学·llm·latex
青春易逝丶28 分钟前
策略模式
java·开发语言·策略模式
freexyn29 分钟前
Matlab入门自学七十四:坐标系转换,直角坐标、极坐标和球坐标的转换
开发语言·算法·matlab
嫂子的姐夫30 分钟前
041-全扣补环境:同花顺
爬虫·python·js逆向·逆向
2401_8942419242 分钟前
机器学习与人工智能
jvm·数据库·python
vx-程序开发1 小时前
springboot在线装修管理系统-计算机毕业设计源码56278
java·c语言·spring boot·python·spring·django·php
Dxy12393102161 小时前
js如何把字符串转数字
开发语言·前端·javascript
进击的雷神1 小时前
主办方过滤、展位号模糊提取、多层级官网爬取、缅文编码解码——缅甸塑料展爬虫四大技术难关攻克纪实
网络·爬虫·python
_饭团1 小时前
字符串函数全解析:12 种核心函数的使用与底层模拟实现
c语言·开发语言·学习·考研·面试·蓝桥杯