05-推导式
本章代码基于 Python 3.11+ 编写
推导式是 Python 的特色语法,用简洁的方式创建序列,提高代码可读性和性能。
本章全面讲解 Python 的列表推导式、字典推导式、集合推导式和生成器表达式。
概念铺垫
为什么需要推导式?一个高效数据转换场景
问题场景: 你需要从一个数字列表中筛选出所有偶数并计算平方。
不使用推导式的方案(循环):
python
# 传统循环方式
numbers: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result: list[int] = []
for n in numbers:
if n % 2 == 0: # 筛选偶数
result.append(n ** 2) # 计算平方
print(result) # 输出:[4, 16, 36, 64, 100]问题:
- 代码较长(4行)
- 需要先创建空列表
使用推导式的解决方案:
python
# 列表推导式(一行搞定)
numbers: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result: list[int] = [n ** 2 for n in numbers if n % 2 == 0]
print(result) # 输出:[4, 16, 36, 64, 100]这就是推导式的价值:简洁高效地转换数据。
推导式解决了什么问题?
推导式的本质是:用声明式语法创建序列。
就像你说"我要所有偶数的平方",而不是"遍历、判断、添加"。Python 帮你完成细节。
推导式的优势:
- 代码简洁:一行代码完成循环
- 可读性好:逻辑集中,意图明确
- 性能更好:比普通循环更快(底层优化)
- 函数式风格:声明式编程
L1 理解层:会用
推导式的最简用法(3分钟上手)
最常见的列表推导式:
python
# 基础列表推导式
squares: list[int] = [x ** 2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
# 带条件的列表推导式
evens: list[int] = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
# 字典推导式
squares_dict: dict[int, int] = {x: x ** 2 for x in range(5)}
print(squares_dict) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}这就是推导式的基本用法。接下来我们详细学习各类推导式。
第一部分:推导式基础
什么是推导式
推导式(Comprehension) 是 Python 特有的一种简洁的序列生成方式,用一行代码完成循环和条件过滤。
┌─────────────────────────────────────────────────────────────┐
│ 推导式的优势 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 代码简洁:一行代码完成循环 │
│ ✅ 可读性好:逻辑集中,意图明确 │
│ ✅ 性能更好:比普通循环更快(底层优化) │
│ ✅ 函数式风格:声明式编程 │
│ │
│ 推导式类型: │
│ • 列表推导式:[x for x in iterable] │
│ • 字典推导式:{k: v for k, v in iterable} │
│ • 集合推导式:{x for x in iterable} │
│ • 生成器表达式:(x for x in iterable) │
│ │
└─────────────────────────────────────────────────────────────┘推导式 vs 传统循环
python
# 传统循环
squares = []
for i in range(1, 6):
squares.append(i ** 2)
print(squares) # [1, 4, 9, 16, 25]
# 列表推导式
squares = [i ** 2 for i in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# 性能对比
import timeit
def traditional_loop():
result = []
for i in range(1000):
result.append(i ** 2)
return result
def comprehension():
return [i ** 2 for i in range(1000)]
print(timeit.timeit(traditional_loop, number=10000))
print(timeit.timeit(comprehension, number=10000))
# 推导式通常快 10-20%第二部分:列表推导式
基本语法
列表推导式: 用一行代码创建列表,替代传统循环。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 列表推导式语法 │
│ │
│ [表达式 for 变量 in 可迭代对象] │
│ ↑ ↑ ↑ ↑ │
│ 结果 遍历 每项 数据源 │
│ │
│ 执行流程: │
│ ┌──────────────────────────────────────────┐ │
│ │ for 变量 in 可迭代对象 │ │
│ │ ↓ │ │
│ │ 表达式 → 结果加入列表 │ │
│ │ ↓ │ │
│ │ 继续下一个元素... │ │
│ └──────────────────────────────────────────┘ │
│ │
│ 示例:[x ** 2 for x in range(5)] │
│ ↓ ↓ ↓ │
│ 平方 变量 数字0-4 │
│ │
│ 结果:[0, 1, 4, 9, 16] │
└─────────────────────────────────────────────────────────────┘最简示例
python
# 创建平方列表
squares = [i ** 2 for i in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]关键代码解释
| 代码 | 含义 | 执行过程 |
|---|---|---|
i ** 2 | 表达式,计算平方 | 对每个 i 计算平方值 |
for i in range(1, 6) | 循环部分 | 遍历 1, 2, 3, 4, 5 |
[] | 列表容器 | 收集所有结果 |
详细示例
python
# 字符串转大写
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']
# 提取属性
persons = [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]
names = [p["name"] for p in persons]
print(names) # ['Alice', 'Bob']带条件的推导式
条件过滤: 在推导式末尾添加 if 条件,只保留满足条件的元素。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 带条件的列表推导式 │
│ │
│ [表达式 for 变量 in 可迭代对象 if 条件] │
│ ↑ ↑ ↑ ↑ ↑ │
│ 结果 遍历 每项 数据源 过滤 │
│ │
│ 执行流程: │
│ ┌──────────────────────────────────────────┐ │
│ │ for 变量 in 可迭代对象 │ │
│ │ ↓ │ │
│ │ if 条件 → True: 表达式 → 加入列表 │ │
│ │ → False: 跳过 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ 示例:[x for x in range(10) if x % 2 == 0] │
│ ↑ ↑ │
│ 数据源 奇数过滤 │
│ │
│ 结果:[0, 2, 4, 6, 8](只保留偶数) │
└─────────────────────────────────────────────────────────────┘最简示例
python
# 只保留偶数
evens = [n for n in range(1, 11) if n % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]关键代码解释
| 代码 | 含义 | 执行过程 |
|---|---|---|
if n % 2 == 0 | 条件判断 | 只保留偶数 |
n | 表达式 | 条件满足时保留原值 |
| 执行顺序 | 先循环 → 后判断 → 再收集 | 条件在循环之后 |
详细示例
python
# 筛选并处理
even_squares = [n ** 2 for n in range(1, 11) if n % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100]
# 过滤字符串
words = ["apple", "", "banana", "", "cherry"]
non_empty = [w for w in words if w] # 空字符串为 False
print(non_empty) # ['apple', 'banana', 'cherry']
# 复杂条件
numbers = range(-5, 6)
positive_evens = [n for n in numbers if n > 0 and n % 2 == 0]
print(positive_evens) # [2, 4]条件表达式(if-else)
条件表达式: 不是过滤,而是根据条件选择不同的值。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 条件表达式(三元运算) │
│ │
│ [表达式1 if 条件 else 表达式2 for 变量 in 可迭代对象] │
│ ↑ ↑ ↑ │
│ 选择 条件 备选 │
│ │
│ ⚠️ 注意区别: │
│ ───────────────────────────────────── │
│ 过滤:if 在末尾 → 不满足条件的元素被跳过 │
│ 选择:if-else 在表达式位置 → 每个元素都保留,值不同 │
│ │
│ 示例对比: │
│ [x for x in range(5) if x % 2 == 0] → [0, 2, 4] │
│ ["偶" if x % 2 == 0 else "奇" for x in range(5)] │
│ → ['偶', '奇',...]│
└─────────────────────────────────────────────────────────────┘最简示例
python
# 奇偶分类(每个元素都保留)
numbers = range(1, 6)
labels = ["偶" if n % 2 == 0 else "奇" for n in numbers]
print(labels) # ['奇', '偶', '奇', '偶', '奇']关键代码解释
| 代码 | 含义 | 区别 |
|---|---|---|
if 在末尾 | 过滤 | 不满足条件的元素跳过 |
if-else 在表达式位置 | 选择 | 每个元素都保留,值不同 |
详细示例
python
# 正负分类
numbers = [-3, -1, 0, 2, 4]
categories = ["负数" if n < 0 else "零" if n == 0 else "正数" for n in numbers]
print(categories) # ['负数', '负数', '零', '正数', '正数']
# 处理缺失值
data = [1, None, 2, None, 3]
cleaned = [x if x is not None else 0 for x in data]
print(cleaned) # [1, 0, 2, 0, 3]嵌套循环
嵌套推导式: 多层 for 循环,展开嵌套结构或生成组合。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 嵌套循环推导式 │
│ │
│ [表达式 for 变量1 in 可迭代对象1 for 变量2 in 可迭代对象2] │
│ ↑ ↑ ↑ ↑ │
│ 外层循环 外层数据 内层循环 内层数据 │
│ │
│ 执行顺序(重要): │
│ ┌──────────────────────────────────────────┐ │
│ │ for 变量1 in 可迭代对象1 ← 外层 │ │
│ │ ↓ │ │
│ │ for 变量2 in 可迭代对象2 ← 内层 │ │
│ │ ↓ │ │
│ │ 表达式 → 加入列表 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ⚠️ 注意:for 的顺序 = 传统循环的顺序 │
│ │
│ 示例:[(x, y) for x in [1,2] for y in ['a','b']] │
│ 结果:[(1,'a'), (1,'b'), (2,'a'), (2,'b')] │
└─────────────────────────────────────────────────────────────┘最简示例
python
# 生成所有组合
colors = ["red", "green"]
sizes = ["S", "M", "L"]
products = [(color, size) for color in colors for size in sizes]
print(products)
# [('red', 'S'), ('red', 'M'), ('red', 'L'),
# ('green', 'S'), ('green', 'M'), ('green', 'L')]关键代码解释
| 代码 | 含义 | 执行顺序 |
|---|---|---|
for color in colors | 外层循环 | 先遍历 colors |
for size in sizes | 内层循环 | 对每个 color 遍历 sizes |
(color, size) | 表达式 | 组合为元组 |
等价传统循环:
python
# 推导式写法
products = [(color, size) for color in colors for size in sizes]
# 传统循环写法(顺序相同)
products = []
for color in colors: # 外层
for size in sizes: # 内层
products.append((color, size))详细示例
python
# 展开嵌套列表(二维转一维)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 带条件的嵌套循环
evens = [num for row in matrix for num in row if num % 2 == 0]
print(evens) # [2, 4, 6, 8]多变量解包
python
# 解包形式
pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
# 解包
result = [f"{num}:{letter}" for num, letter in pairs]
print(result) # ['1:a', '2:b', '3:c']
# 示例:字典项解包
person = {"name": "Alice", "age": 25, "city": "Beijing"}
items = [f"{k}={v}" for k, v in person.items()]
print(items) # ['name=Alice', 'age=25', 'city=Beijing']
# 示例:enumerate 解包
words = ["apple", "banana", "cherry"]
indexed = [f"{i}: {word}" for i, word in enumerate(words)]
print(indexed) # ['0: apple', '1: banana', '2: cherry']第三部分:字典推导式
基本语法
字典推导式: 用一行代码创建字典,生成键值对映射。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 字典推导式语法 │
│ │
│ {键表达式: 值表达式 for 变量 in 可迭代对象} │
│ ↑ ↑ ↑ ↑ ↑ │
│ 键 值 遍历 每项 数据源 │
│ │
│ ⚠️ 注意:使用花括号 {},不是方括号 [] │
│ │
│ 示例:{x: x ** 2 for x in range(5)} │
│ ↑ ↑ │
│ 键 值 │
│ │
│ 结果:{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} │
└─────────────────────────────────────────────────────────────┘最简示例
python
# 创建平方字典
squares = {i: i ** 2 for i in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}关键代码解释
| 代码 | 含义 | 说明 |
|---|---|---|
{} | 字典容器 | 使用花括号 |
i: | 键表达式 | 键为 i 的值 |
i ** 2 | 值表达式 | 值为 i 的平方 |
详细示例
python
# 交换键值对
person = {"name": "Alice", "age": 25}
swapped = {v: k for k, v in person.items()}
print(swapped) # {'Alice': 'name', 25: 'age'}
# 从两个列表创建字典
keys = ["name", "age", "city"]
values = ["Alice", 25, "Beijing"]
person = {k: v for k, v in zip(keys, values)}
print(person) # {'name': 'Alice', 'age': 25, 'city': 'Beijing'}带条件的字典推导式
python
# 示例:只保留值大于 60 的项
scores = {"Alice": 85, "Bob": 60, "Charlie": 45, "David": 92}
passed = {name: score for name, score in scores.items() if score >= 60}
print(passed) # {'Alice': 85, 'Bob': 60, 'David': 92}
# 示例:过滤键
data = {"a": 1, "B": 2, "c": 3, "D": 4}
lowercase_keys = {k: v for k, v in data.items() if k.islower()}
print(lowercase_keys) # {'a': 1, 'c': 3}
# 示例:处理值
prices = {"apple": 100, "banana": 50, "cherry": 200}
discounted = {fruit: price * 0.9 for fruit, price in prices.items()}
print(discounted) # {'apple': 90.0, 'banana': 45.0, 'cherry': 180.0}实际应用
python
# 统计字符频率
text = "hello world"
char_count = {char: text.count(char) for char in set(text)}
print(char_count) # {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}
# 分组
students = [
{"name": "Alice", "grade": "A"},
{"name": "Bob", "grade": "B"},
{"name": "Charlie", "grade": "A"},
{"name": "David", "grade": "C"}
]
# 按成绩分组
from collections import defaultdict
grades = defaultdict(list)
for s in students:
grades[s["grade"]].append(s["name"])
print(dict(grades)) # {'A': ['Alice', 'Charlie'], 'B': ['Bob'], 'C': ['David'}
# 创建映射字典
words = ["apple", "banana", "cherry"]
word_lengths = {word: len(word) for word in words}
print(word_lengths) # {'apple': 5, 'banana': 6, 'cherry': 6}第四部分:集合推导式
基本语法
集合推导式: 用一行代码创建集合,自动去重。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 集合推导式语法 │
│ │
│ {表达式 for 变量 in 可迭代对象} │
│ ↑ ↑ ↑ ↑ │
│ 元素 遍历 每项 数据源 │
│ │
│ ⚠️ 注意: │
│ • 使用花括号 {} │
│ • 自动去重(集合特性) │
│ • 结果无序(集合特性) │
│ │
│ 示例:{x ** 2 for x in [-2, -1, 0, 1, 2]} │
│ │
│ 结果:{0, 1, 4}(-2和2的平方相同,自动去重) │
└─────────────────────────────────────────────────────────────┘最简示例
python
# 创建平方集合(自动去重)
squares = {i ** 2 for i in range(-2, 3)}
print(squares) # {0, 1, 4}(-2²=4 和 2²=4 合并为一个)关键代码解释
| 代码 | 含义 | 说明 |
|---|---|---|
{} | 集合容器 | 使用花括号(同字典) |
| 自动去重 | 集合特性 | 相同元素只保留一个 |
| 无序 | 集合特性 | 不保证顺序 |
详细示例
python
# 列表去重
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = {n for n in numbers}
print(unique) # {1, 2, 3, 4}
# 字符串去重
text = "hello world"
unique_chars = {char for char in text}
print(unique_chars) # {'h', 'e', 'l', 'o', ' ', 'w', 'r', 'd'}带条件的集合推导式
python
# 筛选偶数
numbers = range(1, 11)
even_squares = {n ** 2 for n in numbers if n % 2 == 0}
print(even_squares) # {64, 4, 36, 16, 100}(顺序可能不同)
# 筛选元音
text = "Hello World"
vowels = {char.lower() for char in text if char.lower() in "aeiou"}
print(vowels) # {'e', 'o'}
# 提取唯一首字母
words = ["apple", "apricot", "banana", "cherry", "blueberry"]
first_letters = {word[0] for word in words}
print(first_letters) # {'a', 'b', 'c'}第五部分:生成器表达式
什么是生成器表达式
生成器表达式: 类似列表推导式,但返回生成器对象,惰性计算,节省内存。
语法结构:
┌─────────────────────────────────────────────────────────────┐
│ 生成器表达式语法 │
│ │
│ (表达式 for 变量 in 可迭代对象) │
│ ↑ ↑ ↑ ↑ │
│ 结果 遍历 每项 数据源 │
│ │
│ ⚠️ 注意: │
│ • 使用圆括号 (),不是方括号 [] │
│ • 返回生成器对象,不是列表 │
│ • 惰性计算:按需生成,不预先计算 │
│ • 只能遍历一次 │
│ │
│ 示例:(x ** 2 for x in range(5)) │
│ │
│ 返回:<generator object>(生成器对象) │
└─────────────────────────────────────────────────────────────┘列表推导式 vs 生成器表达式:
┌─────────────────────────────────────────────────────────────┐
│ 列表推导式 vs 生成器表达式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 列表推导式:[x for x in iterable] │
│ • 立即计算所有元素 │
│ • 返回列表 │
│ • 占用内存存储所有元素 │
│ │
│ 生成器表达式:(x for x in iterable) │
│ • 惰性计算,按需生成 │
│ • 返回生成器对象 │
│ • 内存高效,不存储所有元素 │
│ │
│ 选择建议: │
│ • 需要多次遍历 → 列表推导式 │
│ • 只遍历一次 → 生成器表达式 │
│ • 数据量大 → 生成器表达式 │
│ • 需要索引访问 → 列表推导式 │
│ │
└─────────────────────────────────────────────────────────────┘最简示例
python
# 列表推导式
squares_list = [i ** 2 for i in range(5)]
print(squares_list) # [0, 1, 4, 9, 16]
print(type(squares_list)) # <class 'list'>
# 生成器表达式
squares_gen = (i ** 2 for i in range(5))
print(squares_gen) # <generator object <genexpr> at 0x...>
print(type(squares_gen)) # <class 'generator'>关键代码解释
| 代码 | 含义 | 说明 |
|---|---|---|
() | 圆括号 | 生成器表达式语法 |
| 惰性计算 | 不预先计算 | 遍历时才计算 |
| 只遍历一次 | 生成器特性 | 耗尽后无法再次遍历 |
详细示例
python
# 遍历生成器
squares_gen = (i ** 2 for i in range(5))
for square in squares_gen:
print(square) # 0, 1, 4, 9, 16
# 生成器只能遍历一次
squares_gen = (i ** 2 for i in range(3))
print(list(squares_gen)) # [0, 1, 4]
print(list(squares_gen)) # [](已耗尽!)内存优势
python
import sys
# 列表推导式:占用大量内存
big_list = [i ** 2 for i in range(1000000)]
print(f"列表内存: {sys.getsizeof(big_list)} 字节") # 约 8MB
# 生成器表达式:内存占用极小
big_gen = (i ** 2 for i in range(1000000))
print(f"生成器内存: {sys.getsizeof(big_gen)} 字节") # 约 100 字节
# 生成器不存储所有元素,只存储当前状态关键代码解释:
| 方式 | 内存占用 | 原因 |
|---|---|---|
| 列表推导式 | 大(8MB) | 存储 100万个元素 |
| 生成器表达式 | 小(100字节) | 只存储当前状态,按需计算 |
与函数配合
python
# 与 sum() 配合
total = sum(i ** 2 for i in range(100))
print(total) # 328350
# 与 max()/min() 配合
data = [1, -2, 3, -4, 5]
max_abs = max(abs(x) for x in data)
print(max_abs) # 5
# 与 any()/all() 配合
numbers = [2, 4, 6, 8, 10]
has_odd = any(n % 2 != 0 for n in numbers)
print(has_odd) # False
all_positive = all(n > 0 for n in numbers)
print(all_positive) # True
# 与 join() 配合
words = ["hello", "world"]
result = " ".join(word.upper() for word in words)
print(result) # "HELLO WORLD"
# 与 sorted() 配合
students = [("Alice", 85), ("Bob", 90), ("Charlie", 78)]
sorted_by_score = sorted(students, key=lambda x: x[1], reverse=True)
print(sorted_by_score)带条件的生成器表达式
python
# 筛选偶数
evens = (n for n in range(100) if n % 2 == 0)
print(list(evens)[:10]) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 处理文件行
# 假设有一个大文件
# lines = (line.strip() for line in open('large_file.txt') if line.strip())
# 链式处理
numbers = range(100)
result = (n ** 2 for n in numbers if n % 2 == 0)
result = (n for n in result if n < 1000)
print(list(result)) # [0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784, 900]带条件的推导式
python
# 带条件的形式
# [表达式 for 变量 in 可迭代对象 if 条件]
# 示例:只保留偶数
evens = [n for n in range(1, 11) if n % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
# 示例:筛选并处理
even_squares = [n ** 2 for n in range(1, 11) if n % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100]
# 示例:过滤字符串
words = ["apple", "", "banana", "", "cherry"]
non_empty = [w for w in words if w]
print(non_empty) # ['apple', 'banana', 'cherry']
# 示例:复杂条件
numbers = range(-5, 6)
positive_evens = [n for n in numbers if n > 0 and n % 2 == 0]
print(positive_evens) # [2, 4]条件表达式
python
# if-else 表达式(不是过滤,是选择)
# [表达式1 if 条件 else 表达式2 for 变量 in 可迭代对象]
# 示例:奇偶分类
numbers = range(1, 6)
labels = ["偶" if n % 2 == 0 else "奇" for n in numbers]
print(labels) # ['奇', '偶', '奇', '偶', '奇']
# 示例:正负分类
numbers = [-3, -1, 0, 2, 4]
categories = ["负数" if n < 0 else "零" if n == 0 else "正数" for n in numbers]
print(categories) # ['负数', '负数', '零', '正数', '正数']
# 示例:处理缺失值
data = [1, None, 2, None, 3]
cleaned = [x if x is not None else 0 for x in data]
print(cleaned) # [1, 0, 2, 0, 3]嵌套循环
python
# 嵌套循环形式
# [表达式 for 变量1 in 可迭代对象1 for 变量2 in 可迭代对象2]
# 示例:生成所有组合
colors = ["red", "green"]
sizes = ["S", "M", "L"]
products = [(color, size) for color in colors for size in sizes]
print(products)
# [('red', 'S'), ('red', 'M'), ('red', 'L'),
# ('green', 'S'), ('green', 'M'), ('green', 'L')]
# 示例:展开嵌套列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 等价于传统循环
flattened = []
for row in matrix:
for num in row:
flattened.append(num)
# 示例:带条件的嵌套循环
# 找出所有偶数
evens = [num for row in matrix for num in row if num % 2 == 0]
print(evens) # [2, 4, 6, 8]多变量解包
python
# 解包形式
pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
# 解包
result = [f"{num}:{letter}" for num, letter in pairs]
print(result) # ['1:a', '2:b', '3:c']
# 示例:字典项解包
person = {"name": "Alice", "age": 25, "city": "Beijing"}
items = [f"{k}={v}" for k, v in person.items()]
print(items) # ['name=Alice', 'age=25', 'city=Beijing']
# 示例:enumerate 解包
words = ["apple", "banana", "cherry"]
indexed = [f"{i}: {word}" for i, word in enumerate(words)]
print(indexed) # ['0: apple', '1: banana', '2: cherry']第三部分:字典推导式
基本语法
python
# 基本形式
# {键表达式: 值表达式 for 变量 in 可迭代对象}
# 示例:创建平方字典
squares = {i: i ** 2 for i in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 示例:交换键值对
person = {"name": "Alice", "age": 25}
swapped = {v: k for k, v in person.items()}
print(swapped) # {'Alice': 'name', 25: 'age'}
# 示例:从两个列表创建字典
keys = ["name", "age", "city"]
values = ["Alice", 25, "Beijing"]
person = {k: v for k, v in zip(keys, values)}
print(person) # {'name': 'Alice', 'age': 25, 'city': 'Beijing'}带条件的字典推导式
python
# 示例:只保留值大于 60 的项
scores = {"Alice": 85, "Bob": 60, "Charlie": 45, "David": 92}
passed = {name: score for name, score in scores.items() if score >= 60}
print(passed) # {'Alice': 85, 'Bob': 60, 'David': 92}
# 示例:过滤键
data = {"a": 1, "B": 2, "c": 3, "D": 4}
lowercase_keys = {k: v for k, v in data.items() if k.islower()}
print(lowercase_keys) # {'a': 1, 'c': 3}
# 示例:处理值
prices = {"apple": 100, "banana": 50, "cherry": 200}
discounted = {fruit: price * 0.9 for fruit, price in prices.items()}
print(discounted) # {'apple': 90.0, 'banana': 45.0, 'cherry': 180.0}实际应用
python
# 统计字符频率
text = "hello world"
char_count = {char: text.count(char) for char in set(text)}
print(char_count) # {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}
# 分组
students = [
{"name": "Alice", "grade": "A"},
{"name": "Bob", "grade": "B"},
{"name": "Charlie", "grade": "A"},
{"name": "David", "grade": "C"}
]
# 按成绩分组
from collections import defaultdict
grades = defaultdict(list)
for s in students:
grades[s["grade"]].append(s["name"])
print(dict(grades)) # {'A': ['Alice', 'Charlie'], 'B': ['Bob'], 'C': ['David']}
# 创建映射字典
words = ["apple", "banana", "cherry"]
word_lengths = {word: len(word) for word in words}
print(word_lengths) # {'apple': 5, 'banana': 6, 'cherry': 6}第四部分:集合推导式
基本语法
python
# 基本形式
# {表达式 for 变量 in 可迭代对象}
# 示例:创建平方集合
squares = {i ** 2 for i in range(1, 6)}
print(squares) # {1, 4, 9, 16, 25}
# 示例:自动去重
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = {n for n in numbers}
print(unique) # {1, 2, 3, 4}
# 示例:字符串去重
text = "hello world"
unique_chars = {char for char in text}
print(unique_chars) # {'h', 'e', 'l', 'o', ' ', 'w', 'r', 'd'}带条件的集合推导式
python
# 示例:筛选偶数
numbers = range(1, 11)
even_squares = {n ** 2 for n in numbers if n % 2 == 0}
print(even_squares) # {64, 4, 36, 16, 100}
# 示例:筛选元音
text = "Hello World"
vowels = {char.lower() for char in text if char.lower() in "aeiou"}
print(vowels) # {'e', 'o'}
# 示例:提取唯一首字母
words = ["apple", "apricot", "banana", "cherry", "blueberry"]
first_letters = {word[0] for word in words}
print(first_letters) # {'a', 'b', 'c'}第五部分:生成器表达式
什么是生成器表达式
生成器表达式 类似于列表推导式,但返回生成器对象,按需生成元素,节省内存。
┌─────────────────────────────────────────────────────────────┐
│ 列表推导式 vs 生成器表达式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 列表推导式:[x for x in iterable] │
│ • 立即计算所有元素 │
│ • 返回列表 │
│ • 占用内存存储所有元素 │
│ │
│ 生成器表达式:(x for x in iterable) │
│ • 惰性计算,按需生成 │
│ • 返回生成器对象 │
│ • 内存高效,不存储所有元素 │
│ │
│ 选择建议: │
│ • 需要多次遍历 → 列表推导式 │
│ • 只遍历一次 → 生成器表达式 │
│ • 数据量大 → 生成器表达式 │
│ • 需要索引访问 → 列表推导式 │
│ │
└─────────────────────────────────────────────────────────────┘基本用法
python
# 列表推导式
squares_list = [i ** 2 for i in range(5)]
print(squares_list) # [0, 1, 4, 9, 16]
print(type(squares_list)) # <class 'list'>
# 生成器表达式
squares_gen = (i ** 2 for i in range(5))
print(squares_gen) # <generator object <genexpr> at 0x...>
print(type(squares_gen)) # <class 'generator'>
# 遍历生成器
for square in squares_gen:
print(square)
# 生成器只能遍历一次
squares_gen = (i ** 2 for i in range(3))
print(list(squares_gen)) # [0, 1, 4]
print(list(squares_gen)) # [](已耗尽)内存优势
python
import sys
# 列表推导式:占用大量内存
big_list = [i ** 2 for i in range(1000000)]
print(f"列表内存: {sys.getsizeof(big_list)} 字节") # 约 8MB
# 生成器表达式:内存占用极小
big_gen = (i ** 2 for i in range(1000000))
print(f"生成器内存: {sys.getsizeof(big_gen)} 字节") # 约 100 字节
# 生成器不存储所有元素,只存储当前状态与函数配合
python
# 与 sum() 配合
total = sum(i ** 2 for i in range(100))
print(total) # 328350
# 与 max()/min() 配合
data = [1, -2, 3, -4, 5]
max_abs = max(abs(x) for x in data)
print(max_abs) # 5
# 与 any()/all() 配合
numbers = [2, 4, 6, 8, 10]
has_odd = any(n % 2 != 0 for n in numbers)
print(has_odd) # False
all_positive = all(n > 0 for n in numbers)
print(all_positive) # True
# 与 join() 配合
words = ["hello", "world"]
result = " ".join(word.upper() for word in words)
print(result) # "HELLO WORLD"
# 与 sorted() 配合
students = [("Alice", 85), ("Bob", 90), ("Charlie", 78)]
sorted_by_score = sorted(students, key=lambda x: x[1], reverse=True)
print(sorted_by_score)带条件的生成器表达式
python
# 筛选偶数
evens = (n for n in range(100) if n % 2 == 0)
print(list(evens)[:10]) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 处理文件行
# 假设有一个大文件
# lines = (line.strip() for line in open('large_file.txt') if line.strip())
# 链式处理
numbers = range(100)
result = (n ** 2 for n in numbers if n % 2 == 0)
result = (n for n in result if n < 1000)
print(list(result)) # [0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784, 900]第六部分:推导式最佳实践
可读性原则
python
# ✅ 简洁明了
squares = [i ** 2 for i in range(10)]
# ❌ 过于复杂
# result = [x for sublist in matrix for x in sublist if x > 0 if x % 2 == 0]
# ✅ 拆分为多步
flattened = [x for row in matrix for x in row]
positive = [x for x in flattened if x > 0]
even_positive = [x for x in positive if x % 2 == 0]
# ✅ 或使用传统循环
result = []
for row in matrix:
for x in row:
if x > 0 and x % 2 == 0:
result.append(x)
# 经验法则:
# • 超过 2 个 for 或 if,考虑使用传统循环
# • 一行代码超过 80 字符,考虑拆分
# • 逻辑复杂时,优先可读性性能考虑
python
import timeit
# 列表推导式 vs map()
numbers = range(1000)
# 列表推导式
squares_comp = [x ** 2 for x in numbers]
# map()
squares_map = list(map(lambda x: x ** 2, numbers))
# 性能对比
print(timeit.timeit('[x ** 2 for x in range(1000)]', number=10000))
print(timeit.timeit('list(map(lambda x: x ** 2, range(1000)))', number=10000))
# 列表推导式通常更快
# 但 map() 在某些情况下更高效
# 例如使用内置函数
print(timeit.timeit('[str(x) for x in range(1000)]', number=10000))
print(timeit.timeit('list(map(str, range(1000)))', number=10000))
# map(str, ...) 可能更快常见错误
python
# 错误 1:变量作用域泄露(Python 3 已修复)
x = 10
result = [x for x in range(5)]
print(x) # 10(Python 3 中不变)
# 错误 2:修改外部变量
total = 0
# [total := total + x for x in range(5)] # 不推荐
# 使用 sum()
total = sum(range(5))
# 错误 3:生成器耗尽
gen = (x for x in range(3))
print(list(gen)) # [0, 1, 2]
print(list(gen)) # [](已耗尽)
# 错误 4:混淆 if 位置
# 过滤(if 在末尾)
evens = [x for x in range(10) if x % 2 == 0]
# 选择(if-else 在表达式位置)
labels = ["even" if x % 2 == 0 else "odd" for x in range(5)]第七部分:推导式对比总结
┌─────────────────────────────────────────────────────────────┐
│ 推导式对比总结 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 类型 语法 返回类型 │
│ ───────────────────────────────────────────── │
│ 列表推导式 [x for x in iter] list │
│ 字典推导式 {k: v for ...} dict │
│ 集合推导式 {x for x in iter} set │
│ 生成器表达式 (x for x in iter) generator │
│ │
│ 使用场景: │
│ ───────────────────────────────────────────── │
│ 列表推导式:需要索引访问、多次遍历 │
│ 字典推导式:创建映射关系 │
│ 集合推导式:去重、集合运算 │
│ 生成器表达式:大数据、单次遍历、内存敏感 │
│ │
│ 性能特点: │
│ ───────────────────────────────────────────── │
│ 列表推导式:内存占用大,访问快 │
│ 生成器表达式:内存占用小,惰性计算 │
│ │
└─────────────────────────────────────────────────────────────┘从简单到复杂:推导式的渐进应用
层级1:基础转换
python
# 数字平方
squares: list[int] = [x ** 2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]层级2:条件过滤
python
# 筛选偶数
numbers: list[int] = list(range(10))
evens: list[int] = [x for x in numbers if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]层级3:嵌套循环
python
# 生成坐标点
points: list[tuple[int, int]] = [(x, y) for x in range(3) for y in range(3)]
print(points) # [(0,0), (0,1), (0,2), (1,0), ...]层级4:字典推导式
python
# 字符串长度映射
words: list[str] = ["apple", "banana", "cherry"]
word_lengths: dict[str, int] = {w: len(w) for w in words}
print(word_lengths) # {'apple': 5, 'banana': 6, 'cherry': 6}层级5:生成器表达式
python
# 处理大数据(惰性计算)
big_data = range(1000000)
sum_of_squares: int = sum(x ** 2 for x in big_data if x % 2 == 0)
print(sum_of_squares)综合应用:数据处理管道
这个示例综合运用多种推导式:
python
# 数据处理管道(Python 3.11+)
from typing import Any
def process_students(students: list[dict[str, Any]]) -> dict[str, Any]:
"""
处理学生数据
Args:
students: 学生列表
Returns:
处理结果
"""
# 列表推导式:筛选及格学生
passed: list[dict[str, Any]] = [
s for s in students if s["score"] >= 60
]
# 字典推导式:创建学号-姓名映射
id_name_map: dict[int, str] = {
s["id"]: s["name"] for s in students
}
# 列表推导式 + 嵌套:提取所有成绩
all_scores: list[int] = [
score for s in students for score in s.get("scores", [])
]
# 集合推导式:获取唯一课程
courses: set[str] = {s["course"] for s in students}
# 生成器表达式:计算平均分
avg_score: float = sum(s["score"] for s in students) / len(students)
return {
"passed_count": len(passed),
"id_name_map": id_name_map,
"all_scores": all_scores,
"courses": courses,
"average_score": avg_score
}
# 使用示例
students_data: list[dict[str, Any]] = [
{"id": 1, "name": "张三", "score": 85, "course": "数学", "scores": [80, 90, 85]},
{"id": 2, "name": "李四", "score": 92, "course": "数学", "scores": [88, 95, 93]},
{"id": 3, "name": "王五", "score": 58, "course": "物理", "scores": [55, 60, 59]},
]
result: dict[str, Any] = process_students(students_data)
print("=== 处理结果 ===")
print(f"及格人数:{result['passed_count']}")
print(f"平均分:{result['average_score']:.1f}")
print(f"课程:{result['courses']}")
print(f"学号映射:{result['id_name_map']}")这个示例展示了:
- 列表推导式筛选和转换
- 字典推导式创建映射
- 集合推导式去重
- 生成器表达式惰性计算
- 嵌套推导式提取数据
- 类型提示的现代语法
L2 实践层:用好
最佳实践
推导式类型选择指南
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 创建列表并多次使用 | 列表推导式 | 可索引、可重复遍历 |
| 创建键值映射 | 字典推导式 | 一行创建映射 |
| 去重 | 集合推导式 | 自动去重 |
| 大数据处理(单次遍历) | 生成器表达式 | 内存高效 |
| 与 sum/max/any 配合 | 生成器表达式 | 无需中间列表 |
| 需要索引访问 | 列表推导式 | 生成器不支持索引 |
反模式:不要这样做
python
# ❌ 反模式 1:推导式用于副作用
[print(x) for x in range(5)] # 创建无用列表 [None, None, None, None, None]
# ✅ 正确做法:用 for 循环
for x in range(5):
print(x)python
# ❌ 反模式 2:过于复杂的嵌套
result = [x for row in matrix for x in row if x > 0 if x % 2 == 0]
# ✅ 正确做法:拆分或用传统循环
flattened = [x for row in matrix for x in row]
result = [x for x in flattened if x > 0 and x % 2 == 0]python
# ❌ 反模式 3:生成器表达式多次遍历
gen = (x ** 2 for x in range(5))
list(gen) # [0, 1, 4, 9, 16]
list(gen) # [](已耗尽)
# ✅ 正确做法:用列表推导式或重新创建
lst = [x ** 2 for x in range(5)] # 可重复遍历python
# ❌ 反模式 4:混淆过滤 if 和选择 if-else
# 过滤(if 在末尾)- 跳过某些元素
evens = [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]
# 选择(if-else 在表达式)- 每个元素都保留,值不同
labels = ["偶" if x % 2 == 0 else "奇" for x in range(10)] # 10个元素python
# ❌ 反模式 5:用推导式修改外部变量
total = 0
result = [total := total + x for x in range(5)] # 不推荐
# ✅ 正确做法:用内置函数
total = sum(range(5))python
# ❌ 反模式 6:忘记生成器需要函数配合时省略括号
sum([x ** 2 for x in range(100)]) # 创建临时列表
# ✅ 正确做法:直接传生成器(函数调用时括号可省)
sum(x ** 2 for x in range(100)) # 无临时列表,更高效适用场景
| 场景 | 推导式适用 | 原因 |
|---|---|---|
| 数据转换(筛选、映射) | ✅ 推荐 | 声明式,简洁 |
| 简单条件过滤 | ✅ 推荐 | 一行完成 |
| 嵌套遍历(≤2层) | ✅ 推荐 | 比循环简洁 |
| 打印、写入文件 | ❌ 用 for 循环 | 推导式不应有副作用 |
| 需要异常处理 | ❌ 用 for 循环 | 推导式难以处理异常 |
| 嵌套超过2层 | ❌ 用 for 循环 | 可读性下降 |
| 需要多次遍历 | ❌ 用列表而非生成器 | 生成器耗尽 |
性能专项:生成器 vs 列表(大数据)
python
import sys, timeit
# 列表推导式:100万个元素 → 内存暴涨
big_list = [x ** 2 for x in range(1_000_000)]
print(f"列表内存: {sys.getsizeof(big_list) / 1024 / 1024:.1f} MB") # ~8 MB
# 生成器表达式:内存几乎不变
big_gen = (x ** 2 for x in range(1_000_000))
print(f"生成器内存: {sys.getsizeof(big_gen)} bytes") # ~100 bytes
# 与内置函数配合时的性能(省略中间括号)
# ✅ sum() + 生成器 — 无中间列表
print(timeit.timeit('sum(x ** 2 for x in range(100000))', number=100))
# ~0.5s,内存恒定
# ❌ sum() + 列表推导 — 创建完整列表
print(timeit.timeit('sum([x ** 2 for x in range(100000)])', number=100))
# ~0.6s,额外 ~800KB 内存推导式"不该用"的场景
python
# ❌ 反模式 1:推导式用于副作用(打印、写文件)
results = [print(x) for x in range(5)] # 创建无用列表 [None, None, ...]
# ✅ 正确
for x in range(5):
print(x)
# ❌ 反模式 2:嵌套超过 2 层 — 可读性崩溃
matrix = [[[i+j+k for k in range(3)] for j in range(3)] for i in range(3)]
# ✅ 正确:拆分或使用传统循环
matrix = []
for i in range(3):
row = []
for j in range(3):
row.append([i+j+k for k in range(3)])
matrix.append(row)
# ❌ 反模式 3:推导式中 raise 或 try-except
# [x / y for x, y in zip(a, b)] # y=0 → ZeroDivisionError,推导式无法处理
# ✅ 正确
def safe_div(a, b):
try:
return a / b
except ZeroDivisionError:
return float('inf')
results = [safe_div(x, y) for x, y in zip(a, b)]
# ❌ 反模式 4:推导式内修改外部变量(海象运算符滥用)
total = 0
[r := total := total + x for x in range(5)] # 可运行但不推荐
# ✅ 正确:使用内置函数
total = sum(range(5))L3 专家层:深入
底层原理:字节码优化
Python 如何优化推导式
列表推导式在 Python 3 中有专门的字节码指令,比普通循环更高效:
推导式 vs 循环字节码:
┌─────────────────────────────────────────────────────────────┐
│ 字节码对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 列表推导式 [x ** 2 for x in range(5)] │
│ ───────────────────────────────────── │
│ • BUILD_LIST 创建空列表 │
│ • GET_ITER 获取迭代器 │
│ • FOR_ITER + JUMP 循环迭代 │
│ • STORE_FAST 存储变量 │
│ • BINARY_POWER 计算平方 │
│ • LIST_APPEND 添加到列表(优化的!) │
│ │
│ 普通循环 │
│ ───────────────────────────────────── │
│ • BUILD_LIST 创建空列表 │
│ • LOAD_GLOBAL 'range' 加载函数 │
│ • CALL_FUNCTION 调用 │
│ • GET_ITER 获取迭代器 │
│ • FOR_ITER + JUMP 循环迭代 │
│ • LOAD_FAST 'x' 加载变量 │
│ • BINARY_POWER 计算平方 │
│ • LOAD_FAST 'result' 加载列表 │
│ • LOAD_METHOD 'append' 加载方法 │
│ • CALL_METHOD 调用 append(慢!) │
│ • POP_TOP 清理 │
│ │
│ 关键区别: │
│ ───────────────────────────────────── │
│ • LIST_APPEND 比 CALL_METHOD 'append' 快 │
│ • 推导式少几条字节码 │
│ • 推导式有专用优化 │
│ │
└─────────────────────────────────────────────────────────────┘查看字节码
python
import dis
# 推导式字节码
dis.dis("[x ** 2 for x in range(5)]")
# 普通循环字节码
def loop():
result = []
for x in range(5):
result.append(x ** 2)
return result
dis.dis(loop)性能考量
python
import timeit
# 推导式 vs 循环
comp_time = timeit.timeit('[x ** 2 for x in range(1000)]', number=10000)
# ~0.3s
loop_time = timeit.timeit('''
result = []
for x in range(1000):
result.append(x ** 2)
''', number=10000)
# ~0.5s(慢 60%+)
# 生成器 vs 列表内存
import sys
lst = [x ** 2 for x in range(100000)]
gen = (x ** 2 for x in range(100000))
print(f"列表: {sys.getsizeof(lst)} bytes") # ~800KB
print(f"生成器: {sys.getsizeof(gen)} bytes") # ~100 bytes| 方式 | 速度 | 内存 | 说明 |
|---|---|---|---|
| 列表推导式 | 快 | 大 | 字节码优化,预分配 |
| 普通循环 | 较慢 | 大 | append 方法调用开销 |
| 生成器表达式 | 最快创建 | 最小 | 不存储,按需生成 |
| map + lambda | 中等 | 大 | 比推导式稍慢 |
设计动机
| 设计选择 | 原因 | 影响 |
|---|---|---|
| 专用字节码 LIST_APPEND | 性能优化 | 比 append 快 |
| 惰性生成器 | 大数据场景 | 节省内存 |
| 独立作用域(Python 3) | 防止变量泄露 | 推导式变量不影响外部 |
| 简洁语法 | 可读性 | 声明式风格 |
知识关联
推导式知识关联图:
┌─────────────────┐
│ 可迭代对象 │
│ iterable │
└─────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ 列表推导式│ │ 字典推导式│ │ 集合推导式│
│ [x] │ │ {k:v} │ │ {x} │
│ 立即创建 │ │ 键值映射 │ │ 唯一元素 │
└───────────┘ └───────────┘ └───────────┘
│
│ 惰性版本
▼
┌───────────┐
│ 生成器表达式│
│ (x) │
│ 惰性计算 │
│ 节省内存 │
└───────────┘
│
│ 进阶
▼
┌───────────┐
│ 生成器函数 │
│ yield │
│ 更复杂逻辑 │
└───────────┘
对比:
推导式 ──→ 简洁、声明式 ──→ 适合简单场景
for循环 ──→ 灵活 ──→ 适合复杂逻辑/异常处理
map ──→ 函数式 ──→ 内置函数时更快综合性能基准测试
python
import timeit
import sys
n = 100_000
# 1. 列表推导 vs for 循环 vs map
print("=== 创建平方列表 ===")
print(f"列表推导: {timeit.timeit('[x**2 for x in range(1000)]', number=1000):.4f}s")
print(f"for循环: {timeit.timeit('r=[]\nfor x in range(1000): r.append(x**2)', number=1000):.4f}s")
print(f"map(): {timeit.timeit('list(map(lambda x:x**2, range(1000)))', number=1000):.4f}s")
# 2. 内存对比:列表 vs 生成器
lst = [x ** 2 for x in range(n)]
gen = (x ** 2 for x in range(n))
print(f"\n列表内存 (n={n}): {sys.getsizeof(lst) / 1024:.0f} KB")
print(f"生成器内存 (n={n}): {sys.getsizeof(gen)} bytes")
# 3. 带过滤推导 vs filter
print(f"\n=== 过滤偶数 ===")
print(f"推导+if: {timeit.timeit('[x for x in range(10000) if x%2==0]', number=1000):.4f}s")
print(f"filter: {timeit.timeit('list(filter(lambda x:x%2==0, range(10000)))', number=1000):.4f}s")
# 4. 字典推导 vs 传统循环
print(f"\n=== 创建键值映射 ===")
print(f"字典推导: {timeit.timeit('{x:x**2 for x in range(1000)}', number=1000):.4f}s")
print(f"for循环: {timeit.timeit('d={}\nfor x in range(1000): d[x]=x**2', number=1000):.4f}s")
# 5. 生成器表达式与 sum 配合
print(f"\n=== sum() 配合 ===")
print(f"生成器: {timeit.timeit('sum(x**2 for x in range(100000))', number=100):.4f}s")
print(f"列表: {timeit.timeit('sum([x**2 for x in range(100000)])', number=100):.4f}s")| 场景 | 最快方式 | 比最慢快 |
|---|---|---|
| 创建平方列表 (n=1000) | 列表推导 | 比 map ~30% |
| 过滤偶数 (n=10000) | 推导+if | 比 filter ~50% |
| 键值映射 (n=1000) | 字典推导 | 比 for ~40% |
| sum + 大数据 (n=100k) | 生成器 | 省 ~800KB 内存 |
| 内置函数 + 生成器 | genexpr + sum | 不创建中间列表 |
本章小结
┌─────────────────────────────────────────────────────────────┐
│ 推导式 知识要点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 列表推导式: │
│ ✓ [表达式 for 变量 in 可迭代对象] │
│ ✓ [表达式 for 变量 in 可迭代对象 if 条件] │
│ ✓ [表达式 for 变量1 in iter1 for 变量2 in iter2] │
│ │
│ 字典推导式: │
│ ✓ {键: 值 for 变量 in 可迭代对象} │
│ ✓ {键: 值 for 变量 in 可迭代对象 if 条件} │
│ │
│ 集合推导式: │
│ ✓ {表达式 for 变量 in 可迭代对象} │
│ │
│ 生成器表达式: │
│ ✓ (表达式 for 变量 in 可迭代对象) │
│ ✓ 惰性计算、内存高效 │
│ ✓ 只能遍历一次 │
│ │
│ 最佳实践: │
│ ✓ 保持简洁,超过 2 个条件考虑传统循环 │
│ ✓ 大数据用生成器表达式 │
│ ✓ 需要多次遍历用列表推导式 │
│ │
└─────────────────────────────────────────────────────────────┘