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. 遍历序列中的每个元素
  2. 将元素赋值给变量
  3. 计算表达式
  4. 将结果添加到新列表
 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. 用列表推导式生成 1-100 中所有 3 的倍数
  2. 给定列表['Python', 'Java', 'C++', 'Go'],生成一个字典,键是语言名,值是名字长度
  3. 用列表推导式生成一个 3×3 的单位矩阵(对角线为 1,其他为 0)

思考题

列表推导式和传统 for 循环哪个性能更好?为什么?


本文代码示例


相关阅读