目录

第六章:推导式与生成器表达式

本章目标

完成本章学习后,你将能够:

列表推导式

基本语法

# 传统写法
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)  # <generator object <genexpr> 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的标志性特性,简洁而高效。但记住:可读性第一,不要为了使用推导式而牺牲代码清晰度。

下一章:第七章:字符串深度解析