====== 第六章:推导式与生成器表达式 ======
===== 本章目标 =====
完成本章学习后,你将能够:
* 熟练使用列表推导式、字典推导式、集合推导式
* 理解生成器表达式的原理和用法
* 掌握嵌套推导式
* 理解推导式与循环的性能差异
* 在合适的场景选择最佳实现方式
===== 列表推导式 =====
==== 基本语法 ====
# 传统写法
squares = []
for x in range(10):
squares.append(x ** 2)
# 列表推导式
squares = [x ** 2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
语法:'[expression for item in iterable]'
==== 带条件的列表推导式 ====
# 只保留偶数
evens = [x for x in range(20) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 处理符合条件的元素
double_evens = [x * 2 for x in range(20) if x % 2 == 0]
print(double_evens) # [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]
# if-else表达式
labels = ["even" if x % 2 == 0 else "odd" for x in range(10)]
print(labels) # ['even', 'odd', 'even', 'odd', ...]
==== 嵌套列表推导式 ====
# 矩阵转置
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = [[row[i] for row in matrix] for i in range(3)]
print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# 扁平化矩阵
flattened = [x for row in matrix for x in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 组合两个列表
combinations = [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y]
print(combinations) # [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), ...]
===== 字典推导式 =====
==== 基本语法 ====
# 创建平方数字典
squares = {x: x ** 2 for x in range(10)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, ...}
# 从两个列表创建字典
keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = {k: v for k, v in zip(keys, values)}
print(d) # {'a': 1, 'b': 2, 'c': 3}
==== 字典转换 ====
# 交换键值
original = {'a': 1, 'b': 2, 'c': 3}
swapped = {v: k for k, v in original.items()}
print(swapped) # {1: 'a', 2: 'b', 3: 'c'}
# 过滤字典
scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78, 'David': 95}
passed = {k: v for k, v in scores.items() if v >= 80}
print(passed) # {'Alice': 85, 'Bob': 92, 'David': 95}
# 转换值
prices = {'apple': 1.5, 'banana': 0.8, 'cherry': 2.5}
prices_yen = {k: v * 150 for k, v in prices.items()} # 转换为日元
===== 集合推导式 ======
# 基本集合推导式
squares = {x ** 2 for x in range(20)}
print(squares) # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, ...}
# 注意:自动去重,因为集合不允许重复
# 带条件的集合推导式
even_squares = {x ** 2 for x in range(20) if x % 2 == 0}
print(even_squares)
# 从字符串创建集合
unique_chars = {c.lower() for c in "Hello World!" if c.isalpha()}
print(unique_chars) # {'h', 'e', 'l', 'o', 'w', 'r', 'd'}
===== 生成器表达式 =====
==== 什么是生成器 ====
生成器是**惰性求值**的迭代器,只在需要时生成值,节省内存。
# 列表推导式 - 立即计算,占用内存
squares_list = [x ** 2 for x in range(1000000)] # 占用大量内存
# 生成器表达式 - 惰性计算,节省内存
squares_gen = (x ** 2 for x in range(1000000)) # 几乎不占用内存
print(squares_gen) # at 0x...>
# 逐个获取值
print(next(squares_gen)) # 0
print(next(squares_gen)) # 1
print(next(squares_gen)) # 4
==== 生成器的使用 ====
# 遍历生成器
gen = (x ** 2 for x in range(10))
for value in gen:
print(value)
# 转换为列表(会消耗生成器)
gen = (x ** 2 for x in range(10))
print(list(gen)) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# print(list(gen)) # [],生成器已耗尽
# 生成器只能遍历一次
gen = (x for x in range(5))
print(sum(gen)) # 10
print(sum(gen)) # 0,生成器已耗尽
==== 生成器的优势 ====
import sys
# 内存占用对比
list_comp = [x * 2 for x in range(10000)]
gen_expr = (x * 2 for x in range(10000))
print(f"列表推导式: {sys.getsizeof(list_comp)} bytes")
print(f"生成器表达式: {sys.getsizeof(gen_expr)} bytes")
# 处理大数据集
# 假设我们有一个大文件
def process_lines(filename):
# 生成器逐行读取,不占用大量内存
return (line.strip().upper() for line in open(filename))
# 查找包含特定词的行
def find_lines(filename, word):
return (line for line in open(filename) if word in line)
===== 推导式高级技巧 =====
==== 复杂条件 ====
# 多条件筛选
numbers = range(100)
result = [x for x in numbers if x % 2 == 0 if x % 3 == 0]
# 等效于:if x % 2 == 0 and x % 3 == 0
print(result) # [0, 6, 12, 18, ...]
# 嵌套if-else
grades = [85, 92, 78, 65, 55, 95]
categories = [
"优秀" if g >= 90 else "良好" if g >= 80 else "中等" if g >= 70
else "及格" if g >= 60 else "不及格"
for g in grades
]
==== 与函数结合 ====
# 在推导式中调用函数
def process(x):
return x ** 2 + 1
results = [process(x) for x in range(10)]
# 嵌套函数调用
words = ["hello", "WORLD", "PyThOn"]
normalized = [word.strip().lower().capitalize() for word in words]
print(normalized) # ['Hello', 'World', 'Python']
===== 性能比较 =====
import timeit
# 性能测试
list_time = timeit.timeit('[x**2 for x in range(1000)]', number=1000)
loop_time = timeit.timeit('''
result = []
for x in range(1000):
result.append(x**2)
''', number=1000)
map_time = timeit.timeit('list(map(lambda x: x**2, range(1000)))', number=1000)
print(f"列表推导式: {list_time:.4f}s")
print(f"for循环: {loop_time:.4f}s")
print(f"map函数: {map_time:.4f}s")
通常:列表推导式 ≈ map > for循环(列表推导式往往更快且更易读)
===== 何时使用推导式 =====
==== 使用推导式的情况 ====
* 简单的转换和过滤
* 代码简洁且易读
* 结果需要全部存储在内存中(列表)或惰性计算(生成器)
# 好的使用场景
squares = [x**2 for x in range(100)]
evens = [x for x in items if x % 2 == 0]
char_freq = {c: text.count(c) for c in set(text)}
==== 避免使用推导式的情况 ====
* 逻辑过于复杂
* 需要副作用(如打印、修改外部变量)
* 需要多行注释说明
# 避免:过于复杂的推导式
result = [f(x) if x > 0 else g(x) if x < 0 else h(x)
for x in items if x not in excluded]
# 更好:使用普通循环
result = []
for x in items:
if x in excluded:
continue
if x > 0:
result.append(f(x))
elif x < 0:
result.append(g(x))
else:
result.append(h(x))
===== 本章练习 =====
1. **列表推导式练习**:使用一行代码生成1到100中能被3或5整除的数的平方
2. **字典转换**:给定一个字符串列表,创建字典{单词: 长度}
3. **集合去重**:给定嵌套列表[[1,2,2], [3,3,4], [1,2]],获取所有唯一元素
4. **生成器实战**:创建一个生成器产生斐波那契数列
5. **矩阵操作**:使用嵌套推导式实现矩阵乘法
===== 本章小结 =====
本章我们学习了:
* 列表、字典、集合推导式的语法
* 嵌套推导式的使用
* 生成器表达式的惰性求值特性
* 推导式的性能优势
* 何时使用推导式,何时使用普通循环
列表推导式是Python的标志性特性,简洁而高效。但记住:可读性第一,不要为了使用推导式而牺牲代码清晰度。
下一章:[[python_course:chapter07|第七章:字符串深度解析]]