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

### 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）核心操作

```python

# 创建迭代器：将可迭代对象（列表/字符串）转为迭代器
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）类型与操作

###### ① 生成器推导式

```python

gen = (x*2 for x in range(5))  # 生成器对象（初始无任何元素）
print(next(gen))  # 0 （按需生成）
print(next(gen))  # 2 （按需生成）
```

###### ② 生成器函数（带`yield`）

```python

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()`传值（双向通信），比如：
    
    ```python
    
    def gen():
        while True:
            x = yield
            yield x*2
    
    g = gen()
    next(g)        # 启动生成器
    print(g.send(3))  # 6 （传入3，返回3*2）
    ```
    

### 三、三者核心区别对比

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