Skip to content
鼓励作者:欢迎打赏犒劳

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 字节!

如有转载或 CV 的请标注本站原文地址