Skip to main content

Command Palette

Search for a command to run...

Python推导式、迭代器和生成器的对比

Updated
•2 min read•View as Markdown
T
确定性世界里,一个被允许的异常

Python推导式、迭代器和生成器的对比

一、形象比喻(快速理解)

  1. 推导式:“批量生产 + 装满货箱”

推导式本质是 “一次性生产所有元素,直接装满货箱(容器:列表 / 字典 / 集合)”:

  • 你告诉工厂 “按规则生产 100 个零件”,工厂会立刻把 100 个零件全做出来,装进货箱(比如列表)里交给你;

  • 货箱里的元素是实实在在存在的,占用内存,你可以随时开箱拿任意一个(比如list[5]);

  • 就像你买一箱苹果,商家直接给你装满一箱,你当场就能数、能挑。

比如列表推导式[x*2 for x in range(5)],会直接生成[0,2,4,6,8]这个 “装满的货箱”。

  1. 迭代器:“按单取货(货箱已备好)”

迭代器是 “货箱已经装满,但你一次只取一个,取完为止”:

  • 货箱里的元素早就存在(比如列表转的迭代器iter([0,2,4,6,8])),只是你不能直接翻箱,必须 “喊一声取一个”(next());

  • 取走一个就少一个,不能回头取已经拿过的(比如取了第 3 个,就不能再拿第 2 个);

  • 像自动售货机,货道里的饮料早就备好,你按一次出一瓶,直到卖完。

  1. 生成器:“按需生产 + 现做现送”

生成器是 “没有现成货箱,客户要一个才生产一个,生产完直接送走,不囤货”:

  • 工厂里没有成品,你要一个零件,工厂才临时做一个给你,做完不存,接着做下一个;

  • 完全不占用 “囤货的内存”,哪怕要生产 100 万个,也只在生产当下占用一点点资源;

  • 像现做现卖的奶茶店,你点一杯才做一杯,做完直接给你,店里不囤成品奶茶。

二、核心知识点总结

1. 推导式

本质:用简洁语法批量生成容器(列表 / 字典 / 集合)的工具,一次性生成所有元素并存储。

(1)类型与操作
类型 语法 示例
列表推导式 [表达式 for 变量 in 可迭代 if 条件] [x*2 for x in range(5) if x%2==0] → [0, 4, 8]
字典推导式 {键:值 for 变量 in 可迭代 if 条件} {x:x*2 for x in range(5)} → {0:0, 1:2, 2:4, 3:6, 4:8}
集合推导式 {表达式 for 变量 in 可迭代 if 条件} {x*2 for x in range(5)} → {0, 2, 4, 6, 8}
(2)注意点
  • ⚠️ 一次性生成所有元素,占用内存与元素数量正相关(不适合超大数据集,比如生成 100 万元素的列表会直接占满内存);

  • ✅ 支持嵌套循环(如[x for row in [[1,2],[3,4]] for x in row]展平矩阵),但嵌套超过 2 层可读性会暴跌;

  • ❌ 仅用于 “生成容器”,无法直接嵌入打印、延迟等动作(需结合普通循环)。

2. 迭代器

本质:实现了__iter__()和__next__()方法的对象,按需逐个返回元素(不提前存储)。

(1)核心操作

# 创建迭代器:将可迭代对象(列表/字符串)转为迭代器
my_iter = iter([1, 2, 3])  

# 取值:调用next()逐个获取(惰性!)
print(next(my_iter))  # 1 (首次计算)
print(next(my_iter))  # 2 (第二次计算)
print(next(my_iter))  # 3 (第三次计算)
# next(my_iter)  # ❌ 无元素时抛StopIteration异常
(2)注意点
  • ✅ 惰性取值:仅在调用next()时返回元素,节省内存(哪怕是 100 万元素的列表转迭代器,初始内存占用几乎为 0);

  • ⚠️ 一次性遍历:元素取出后无法回溯(比如取了第 3 个元素,就不能再拿第 2 个,需重新创建迭代器);

  • ❗ 可迭代对象(如列表[1,2,3])≠ 迭代器:可迭代对象需通过iter()转为迭代器才能用next()。

3. 生成器

本质:特殊的迭代器(自动实现迭代器协议),通过yield或推导式创建,按需生成元素。

(1)类型与操作
① 生成器推导式

gen = (x*2 for x in range(5))  # 生成器对象(初始无任何元素)
print(next(gen))  # 0 (按需生成)
print(next(gen))  # 2 (按需生成)
② 生成器函数(带yield)

def my_generator():
    for i in range(3):
        yield i*2  # 暂停函数,返回值;下次next()从这里继续

gen = my_generator()
print(next(gen))  # 0
print(next(gen))  # 2
print(next(gen))  # 4
(2)注意点
  • ✅ 极致惰性:yield暂停函数执行,下次next()才继续生成(真正 “现做现卖”,无限序列也能处理,比如(x for x in itertools.count()));

  • ⚠️ 同样一次性遍历:生成器耗尽后无法复用(需重新调用生成器函数 / 推导式);

  • ✨ 高级操作:生成器函数可通过send()传值(双向通信),比如:

    
    def gen():
        while True:
            x = yield
            yield x*2
    
    g = gen()
    next(g)        # 启动生成器
    print(g.send(3))  # 6 (传入3,返回3*2)
    

三、三者核心区别对比

特性 推导式 迭代器 生成器
元素存储 📦 一次性存储所有元素 🚫 不存储元素(按需取) 🚫 不存储元素(按需生成)
内存占用 🚨 高(与元素数量相关) 🟢 低(仅存状态) 🟢 极低(零库存)
遍历特性 🔄 可重复遍历 ⚡ 一次性遍历 ⚡ 一次性遍历
适用场景 小数据集生成容器 按需读取已有数据 动态生成数据(超大 / 无限序列)

More from this blog

离散数学5.1-二元关系一

一、有序对和笛卡尔积 1、有序对(序偶):由两个元素 x 和 y 按照确定顺序排列组成的二元组,记作⟨x, y⟩ 2、笛卡尔积:以 A 中元素为第一元、B 中元素为第二元,构造所有有序对⟨x,y⟩; 由全部这类有序对构成的集合,称为 A 与 B 的笛卡尔积,记作 AXB 例题: 已知 A={a,b}, B={0,1,2},求笛卡尔积 A × B、B × A A × B(前元取自 A,后元取自 B

Jun 25, 20261 min read14
离散数学5.1-二元关系一
天

天创域

37 posts

欢迎来到天创的博客