Python 教程 08:列表推导式入门
“简洁是智慧的灵魂。” —— 莎士比亚
列表推导式是 Python 最具特色的语法之一,它让你用一行代码完成原本需要多行循环才能实现的功能。这不仅是代码的简化,更是思维方式的提升。
1. 什么是列表推导式
列表推导式(List Comprehension)是一种简洁的创建列表的方式。
传统方法:
1# 生成1-10的平方
2squares = []
3for i in range(1, 11):
4 squares.append(i ** 2)
5print(squares) # [1, 4, 9, 16, ..., 100]
列表推导式:
1# 一行搞定
2squares = [i ** 2 for i in range(1, 11)]
3print(squares) # [1, 4, 9, 16, ..., 100]
代码从 3 行变成 1 行,清晰简洁,这就是 Python 的魅力。
2. 基本语法
1[表达式 for 变量 in 序列]
执行过程:
- 遍历序列中的每个元素
- 将元素赋值给变量
- 计算表达式
- 将结果添加到新列表
1# 示例
2numbers = [1, 2, 3, 4, 5]
3
4# 每个数乘以2
5doubled = [n * 2 for n in numbers]
6print(doubled) # [2, 4, 6, 8, 10]
7
8# 转换为字符串
9str_list = [str(n) for n in numbers]
10print(str_list) # ['1', '2', '3', '4', '5']
11
12# 调用方法
13names = ['alice', 'bob', 'charlie']
14capitalized = [name.capitalize() for name in names]
15print(capitalized) # ['Alice', 'Bob', 'Charlie']
3. 带条件的列表推导式
可以添加 if 条件进行过滤:
1[表达式 for 变量 in 序列 if 条件]
1# 筛选偶数
2numbers = range(1, 11)
3evens = [n for n in numbers if n % 2 == 0]
4print(evens) # [2, 4, 6, 8, 10]
5
6# 筛选并转换
7words = ['apple', 'banana', 'cherry', 'date']
8long_words = [w.upper() for w in words if len(w) > 5]
9print(long_words) # ['BANANA', 'CHERRY']
10
11# 过滤负数并求平方
12nums = [-2, -1, 0, 1, 2, 3]
13positive_squares = [n ** 2 for n in nums if n > 0]
14print(positive_squares) # [1, 4, 9]
4. 带 if-else 的列表推导式
if-else 要放在 for 前面:
1[表达式1 if 条件 else 表达式2 for 变量 in 序列]
1# 奇数平方,偶数不变
2numbers = range(1, 11)
3result = [n ** 2 if n % 2 == 1 else n for n in numbers]
4print(result) # [1, 2, 9, 4, 25, 6, 49, 8, 81, 10]
5
6# 标记正负数
7nums = [-2, -1, 0, 1, 2]
8labels = ['负' if n < 0 else ('零' if n == 0 else '正') for n in nums]
9print(labels) # ['负', '负', '零', '正', '正']
区别:
- 只有 if:过滤,生成的列表可能更短
- if-else:转换,生成的列表长度不变
5. 嵌套列表推导式
处理二维列表或嵌套结构:
1# 二维列表展平
2matrix = [
3 [1, 2, 3],
4 [4, 5, 6],
5 [7, 8, 9]
6]
7
8# 方法1:先外层后内层
9flat = [num for row in matrix for num in row]
10print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
11
12# 等价的传统写法
13flat = []
14for row in matrix:
15 for num in row:
16 flat.append(num)
17
18# 生成九九乘法表
19table = [f"{i}×{j}={i*j}" for i in range(1, 10) for j in range(1, i+1)]
20print(table[:5]) # ['1×1=1', '2×1=2', '2×2=4', '3×1=3', '3×2=6']
6. 其他推导式
Python 还有字典推导式、集合推导式:
字典推导式
1{键表达式: 值表达式 for 变量 in 序列}
1# 创建字典
2numbers = range(1, 6)
3squares_dict = {n: n ** 2 for n in numbers}
4print(squares_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
5
6# 交换字典键值
7original = {'a': 1, 'b': 2, 'c': 3}
8swapped = {v: k for k, v in original.items()}
9print(swapped) # {1: 'a', 2: 'b', 3: 'c'}
10
11# 筛选字典
12scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78, 'David': 95}
13passed = {name: score for name, score in scores.items() if score >= 80}
14print(passed) # {'Alice': 85, 'Bob': 92, 'David': 95}
集合推导式
1{表达式 for 变量 in 序列}
1# 去重并转换
2numbers = [1, 1, 2, 2, 3, 3]
3unique_squares = {n ** 2 for n in numbers}
4print(unique_squares) # {1, 4, 9}
5
6# 提取首字母
7words = ['apple', 'banana', 'apricot', 'blueberry', 'cherry']
8first_letters = {w[0] for w in words}
9print(first_letters) # {'a', 'b', 'c'}
7. 生成器表达式
把方括号换成圆括号,就变成生成器:
1# 列表推导式:立即生成所有元素
2squares_list = [i ** 2 for i in range(10)]
3print(type(squares_list)) # <class 'list'>
4
5# 生成器表达式:惰性计算
6squares_gen = (i ** 2 for i in range(10))
7print(type(squares_gen)) # <class 'generator'>
8
9# 需要时才计算
10for sq in squares_gen:
11 print(sq, end=' ')
区别:
- 列表推导式:内存中创建完整列表
- 生成器表达式:按需生成,节省内存
大数据集用生成器更高效。
8. 实际应用
应用 1:数据清洗
1# 清洗用户输入
2inputs = [' Alice ', 'bob', ' Charlie\n']
3cleaned = [name.strip().capitalize() for name in inputs]
4print(cleaned) # ['Alice', 'Bob', 'Charlie']
应用 2:文件处理
1# 读取文件并处理(假设文件存在)
2with open('data.txt') as f:
3 numbers = [int(line.strip()) for line in f if line.strip().isdigit()]
应用 3:坐标变换
1# 笛卡尔积
2colors = ['红', '黑']
3sizes = ['S', 'M', 'L']
4products = [f"{color}-{size}" for color in colors for size in sizes]
5print(products)
6# ['红-S', '红-M', '红-L', '黑-S', '黑-M', '黑-L']
9. 注意事项
不要过度使用
虽然列表推导式很强大,但不要为了炫技而牺牲可读性:
1# 可读性差(不推荐)
2result = [[i*j for i in range(1, 10)] for j in range(1, 10) if sum([i*j for i in range(1, 10)]) > 100]
3
4# 应该拆分成多行或用传统循环
原则:如果列表推导式超过 2 行,或者逻辑复杂,就用传统 for 循环。
避免副作用
列表推导式应该是"纯函数",不要有副作用:
1# 不好的例子
2count = 0
3result = [count := count + 1 for _ in range(5)]
4
5# 应该用传统循环
6count = 0
7result = []
8for _ in range(5):
9 count += 1
10 result.append(count)
10. 小结
今天我们学习了列表推导式:
- 基本语法:
[表达式 for 变量 in 序列] - 带条件:
[表达式 for 变量 in 序列 if 条件] - if-else:
[表达式1 if 条件 else 表达式2 for 变量 in 序列] - 嵌套:多层 for 循环
- 其他推导式:字典、集合
- 生成器表达式:节省内存
列表推导式是 Python 的精髓之一,掌握它能让你的代码更 Pythonic、更优雅。但记住:清晰比简洁更重要。
练习题:
- 用列表推导式生成 1-100 中所有 3 的倍数
- 给定列表
['Python', 'Java', 'C++', 'Go'],生成一个字典,键是语言名,值是名字长度 - 用列表推导式生成一个 3×3 的单位矩阵(对角线为 1,其他为 0)
思考题:
列表推导式和传统 for 循环哪个性能更好?为什么?
本文代码示例: