Python 中,集合推导式(set comprehension)和生成器表达式(generator expression)拥有相似的语法:{i for i in iterable}(i for i in iterable)
但二者在求值时机上有所不同。
集合推导式:立即求值
集合推导式会在创建时立即遍历可迭代对象,并生成最终的 set 对象。例如:array = [1, 2, 3]# 在执行下一行代码时,Python 会遍历 `array`,并根据集合推导式的逻辑进行过滤。x = {i for i in array if array.count(i) > 1}# append 操作不会影响集合推导式的结果array.append(1)print(x) # 输出 set()
生成器表达式:惰性求值
和集合推导式不同,生成器表达式采用惰性求值。例如: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 就不再是同一个对象了,很容易让人误解。
示例代码: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],所以在求值时,实际执行的是:(i for i in [1, 2, 3] if [3, 3, 6].count(i) > 1)
总结
| 类型 | 求值时机 | 创建时保存 | 后续修改影响 |
|---|---|---|---|
集合推导式 {} | 创建时立即执行 | 最终 set 结果 | 不影响 |
生成器表达式 () | 使用时执行 | iterable 引用 + 计算逻辑 | 可能影响 |