Python 推导式与生成器表达式
Python 推导式与生成器表达式
它们都属于一种简洁的迭代语法,基本结构是:
1 | 结果表达式 for 变量 in 可迭代对象 if 条件 |
其中:
for:遍历可迭代对象if:可选,用来筛选元素- 最外层符号决定最终生成的对象类型
1. 列表推导式
语法:
1 | [表达式 for 变量 in iterable if 条件] |
结果是一个 list。
1 | squares = [x ** 2 for x in range(5)] |
加入筛选条件:
1 | even_squares = [x ** 2 for x in range(10) if x % 2 == 0] |
等价于:
1 | even_squares = [] |
列表推导式会立即计算所有元素,并将结果全部保存在内存中。
2. 集合推导式
语法:
1 | {表达式 for 变量 in iterable if 条件} |
结果是一个 set,因此元素会自动去重。
1 | numbers = [1, 2, 2, 3, 3, 3] |
集合是无序的,因此不能依赖输出顺序。
3. 字典推导式
语法:
1 | {键表达式: 值表达式 for 变量 in iterable if 条件} |
结果是一个 dict。
1 | squares = {x: x ** 2 for x in range(5)} |
筛选偶数:
1 | even_squares = { |
字典的键必须是可哈希对象,并且重复的键会被后面的值覆盖。
4. 生成器表达式
语法:
1 | (表达式 for 变量 in iterable if 条件) |
结果是一个生成器对象 generator。
1 | generator = (x ** 2 for x in range(5)) |
生成器不会立即计算全部结果,而是在需要数据时逐个生成:
1 | generator = (x ** 2 for x in range(5)) |
也可以使用循环消费:
1 | for value in generator: |
生成器的特点
- 惰性计算:用到一个才计算一个。
- 节省内存:不会一次性保存所有结果。
- 通常只能完整遍历一次。
- 适合处理大量数据或数据流。
1 | generator = (x for x in range(3)) |
第二次为空,是因为生成器已经被消费完了。
严格来说,列表、集合和字典形式叫做
comprehension;圆括号形式通常叫做生成器表达式generator expression,不叫“生成器推导式”。
any() 与 all()
生成器表达式经常和 any()、all() 配合使用,因为三者都支持短路计算。
1. any()
语法:
1 | any(iterable) |
只要可迭代对象中存在一个真值,就返回 True。
1 | numbers = [1, 3, 5, 8] |
含义是:
是否至少存在一个偶数?
逻辑上类似:
1 | for x in numbers: |
any() 的短路
一旦找到第一个真值,后面的元素就不会继续检查。
1 | any([False, False, True, False]) |
空可迭代对象:
1 | any([]) |
2. all()
语法:
1 | all(iterable) |
只有可迭代对象中的所有元素都是真值,才返回 True。
1 | numbers = [2, 4, 6, 8] |
含义是:
是否所有数字都是偶数?
逻辑上类似:
1 | for x in numbers: |
all() 的短路
一旦遇到第一个假值,后面的元素就不会继续检查。
1 | all([True, True, False, True]) |
空可迭代对象:
1 | all([]) |
这是因为空集合中不存在“不满足条件”的元素,也称为“空真”。
为什么搭配生成器表达式
下面两种写法都能工作:
1 | any([x > 100 for x in numbers]) |
1 | any(x > 100 for x in numbers) |
但第二种更推荐:
1 | any(x > 100 for x in numbers) |
原因是:
- 列表推导式会先计算全部结果,生成一个完整列表。
- 生成器表达式逐个计算。
any()找到一个True就结束。all()找到一个False就结束。- 因此生成器表达式通常更节省内存,也可能更快。
例如:
1 | numbers = range(1_000_000) |
检查到 3 时就会立即停止,不需要处理后面的数字。
常用示例
判断是否存在负数
1 | numbers = [3, 7, -2, 10] |
判断是否全部及格
1 | scores = [80, 65, 90, 72] |
判断字符串是否包含数字
1 | text = "Python3" |
判断密码是否全部由字母和数字构成
1 | password = "abc123" |
不过这个例子中也可以直接写:
1 | is_valid = password.isalnum() |
外层符号总结
| 语法 | 名称 | 结果类型 |
|---|---|---|
[x for x in iterable] |
列表推导式 | list |
{x for x in iterable} |
集合推导式 | set |
{k: v for ...} |
字典推导式 | dict |
(x for x in iterable) |
生成器表达式 | generator |
记忆方式:
1 | [] → list |
最后送宝宝一句口诀:
要完整结果,用列表推导式;
要去重,用集合推导式;
要键值映射,用字典推导式;
要省内存、配合any()和all(),优先用生成器表达式。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 楠瓜的小窝!
评论





