﻿---
title: "Python 中集合推导式与生成器表达式的求值时机"
excerpt: "如题，Python 中集合推导式和生成器表达式的求值时机不同，容易踩坑。"
tags:
  - Python
date: 2026-08-07 00:08:57
updated: 2026-08-07 00:09:54
---

Python 中，集合推导式（set comprehension）和生成器表达式（generator expression）拥有相似的语法：

```python
{i for i in iterable}
(i for i in iterable)
```

但二者在求值时机上有所不同。

## 集合推导式：立即求值

集合推导式会在创建时立即遍历可迭代对象，并生成最终的 `set` 对象。例如：

```python
array = [1, 2, 3]
# 在执行下一行代码时，Python 会遍历 `array`，并根据集合推导式的逻辑进行过滤。
x = {i for i in array if array.count(i) > 1}
# append 操作不会影响集合推导式的结果
array.append(1)
print(x)  # 输出 set()
```

## 生成器表达式：惰性求值

和集合推导式不同，生成器表达式采用惰性求值。例如：

```python
array = [1, 2, 3]
# 在执行下一行代码时，Python 只是创建了一个 `generator` 对象，并保存了生成器表达式的执行逻辑。
x = (i for i in array if array.count(i) > 1)
array.append(1)
# 在执行下一行代码时，Python 会开始遍历 `array`，并根据生成器表达式的逻辑进行过滤。
print(list(x))  # 输出 [1, 1]
```

### 可能踩坑的点

在创建生成器表达式时，Python 会保存对 `array` 的引用，所以后面如果修改了`array`变量的指向，那么生成器里的两个 `array` 就不再是同一个对象了，很容易让人误解。

示例代码:

```python
array = [1, 2, 3]
x = (i for i in array if array.count(i) > 1)
array = [3, 3, 6]
print(list(x))  # 输出 [3]
```

前一个`array`是指向`[1, 2, 3]`，后一个`array`是指向`[3, 3, 6]`，所以在求值时，实际执行的是:

```python
(i for i in [1, 2, 3] if [3, 3, 6].count(i) > 1)
```

## 总结

| 类型              | 求值时机       | 创建时保存               | 后续修改影响 |
| ----------------- | -------------- | ------------------------ | ------------ |
| 集合推导式 `{}`   | 创建时立即执行 | 最终 set 结果            | 不影响       |
| 生成器表达式 `()` | 使用时执行     | iterable 引用 + 计算逻辑 | 可能影响     |
