
python的生成器
这三个概念是 Python 函数式编程的核心,从简单到复杂依次是:推导式(快速创建序列)→ 生成器(惰性求值)→ 迭代器(底层机制)。
一个简单的类比:
- 推导式:就像一次做100个包子,全做好放桌上(一次性生成所有数据,占用内存)。
- 生成器:就像有个包子师傅,你要一个他做一个(惰性求值,节省内存)。
- 迭代器:就像从师傅那里取包子的动作规范,规定了如何拿下一个包子(访问数据的协议)。
1. 推导式
一句话定义:一种简洁的语法,可以从一个序列快速创建另一个序列。
作用:简化 for 循环,代码更优雅。
常见类型
- 列表推导式
[表达式 for 变量 in 可迭代对象] - 字典推导式
{键:值 for 变量 in 可迭代对象} - 集合推导式
{表达式 for 变量 in 可迭代对象}
代码示例
python
# 1. 列表推导式:生成0-9的平方
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 等价于传统写法
squares_traditional = []
for x in range(10):
squares_traditional.append(x**2)
# 2. 带条件的列表推导式:只取偶数
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
# 3. 字典推导式:快速构建映射
names = ['Alice', 'Bob', 'Charlie']
name_len = {name: len(name) for name in names}
print(name_len) # {'Alice': 5, 'Bob': 3, 'Charlie': 7}
# 4. 集合推导式:自动去重
nums = [1, 2, 2, 3, 3, 3]
unique = {x for x in nums}
print(unique) # {1, 2, 3}适用场景
- 对列表/集合/字典做简单的映射和过滤
- 数据量较小(几百到几千个元素)
- 需要立即使用所有数据
2. 迭代器
一句话定义:实现了 __iter__() 和 __next__() 方法的对象,可以逐个返回元素。
本质:Python 中 for 循环工作的底层机制。
核心理解
- 可迭代对象 (Iterable):能用
for循环的(如列表、字符串、文件) - 迭代器 (Iterator):可以用
next()函数获取下一个值的对象
代码示例
python
# 手动使用迭代器
my_list = [1, 2, 3]
iterator = iter(my_list) # 获取迭代器
print(next(iterator)) # 1
print(next(iterator)) # 2
print(next(iterator)) # 3
# print(next(iterator)) # 这里会抛出 StopIteration 异常
# for 循环本质上就是不断调用 next()
for item in my_list:
print(item) # 等价于上面的手动调用
# 判断是否可迭代
from collections.abc import Iterable, Iterator
print(isinstance([1, 2, 3], Iterable)) # True,列表是可迭代对象
print(isinstance([1, 2, 3], Iterator)) # False,列表本身不是迭代器
print(isinstance(iter([1, 2, 3]), Iterator)) # True,iter() 转换后是迭代器适用场景
- 通常不直接使用,而是理解其机制
- 需要手动控制循环过程
- 实现自定义的迭代逻辑
3. 生成器
一句话定义:一种特殊的迭代器,使用 yield 关键字,可以边循环边计算,不一次性生成所有数据。
核心优势:惰性求值,节省内存。
两种创建方式
- 生成器函数:用
yield代替return - 生成器表达式:用小括号
()代替列表推导式的方括号[]
代码示例
python
# 方式1:生成器函数
def count_up_to(n):
"""生成从 0 到 n 的数字"""
i = 0
while i <= n:
yield i # 产出 i,函数暂停,下次 next() 时继续
i += 1
# 使用生成器
counter = count_up_to(3)
print(next(counter)) # 0
print(next(counter)) # 1
print(next(counter)) # 2
print(next(counter)) # 3
# print(next(counter)) # StopIteration
# 可以用 for 循环遍历
for num in count_up_to(3):
print(num) # 0, 1, 2, 3
# 方式2:生成器表达式
gen = (x**2 for x in range(10))
print(gen) # <generator object <genexpr> at 0x...>
print(next(gen)) # 0
print(next(gen)) # 1
print(list(gen)) # 剩余的:[4, 9, 16, 25, 36, 49, 64, 81]
# 对比列表推导式的内存占用(重点!)
import sys
list_comp = [x for x in range(1000000)] # 列表:立即生成,占用内存大
gen_expr = (x for x in range(1000000)) # 生成器:几乎不占内存
print(sys.getsizeof(list_comp)) # 大约 8MB
print(sys.getsizeof(gen_expr)) # 大约 112 字节!
