Python 教程 08:列表推导式入门

“简洁是智慧的灵魂。” —— 莎士比亚

列表推导式是 Python 最具特色的语法之一,它让你用一行代码完成原本需要多行循环才能实现的功能。这不仅是代码的简化,更是思维方式的提升。

1. 什么是列表推导式

列表推导式(List Comprehension)是一种简洁的创建列表的方式。

传统方法

# 生成1-10的平方
squares = []
for i in range(1, 11):
    squares.append(i ** 2)
print(squares)  # [1, 4, 9, 16, ..., 100]

列表推导式

# 一行搞定
squares = [i ** 2 for i in range(1, 11)]
print(squares)  # [1, 4, 9, 16, ..., 100]

代码从 3 行变成 1 行,清晰简洁,这就是 Python 的魅力。

2. 基本语法

[表达式 for 变量 in 序列]

执行过程

  1. 遍历序列中的每个元素
  2. 将元素赋值给变量
  3. 计算表达式
  4. 将结果添加到新列表
# 示例
numbers = [1, 2, 3, 4, 5]

# 每个数乘以2
doubled = [n * 2 for n in numbers]
print(doubled)  # [2, 4, 6, 8, 10]

# 转换为字符串
str_list = [str(n) for n in numbers]
print(str_list)  # ['1', '2', '3', '4', '5']

# 调用方法
names = ['alice', 'bob', 'charlie']
capitalized = [name.capitalize() for name in names]
print(capitalized)  # ['Alice', 'Bob', 'Charlie']

3. 带条件的列表推导式

可以添加 if 条件进行过滤:

[表达式 for 变量 in 序列 if 条件]
# 筛选偶数
numbers = range(1, 11)
evens = [n for n in numbers if n % 2 == 0]
print(evens)  # [2, 4, 6, 8, 10]

# 筛选并转换
words = ['apple', 'banana', 'cherry', 'date']
long_words = [w.upper() for w in words if len(w) > 5]
print(long_words)  # ['BANANA', 'CHERRY']

# 过滤负数并求平方
nums = [-2, -1, 0, 1, 2, 3]
positive_squares = [n ** 2 for n in nums if n > 0]
print(positive_squares)  # [1, 4, 9]

4. 带 if-else 的列表推导式

if-else 要放在 for 前面:

[表达式1 if 条件 else 表达式2 for 变量 in 序列]
# 奇数平方,偶数不变
numbers = range(1, 11)
result = [n ** 2 if n % 2 == 1 else n for n in numbers]
print(result)  # [1, 2, 9, 4, 25, 6, 49, 8, 81, 10]

# 标记正负数
nums = [-2, -1, 0, 1, 2]
labels = ['负' if n < 0 else ('零' if n == 0 else '正') for n in nums]
print(labels)  # ['负', '负', '零', '正', '正']

区别

  • 只有 if:过滤,生成的列表可能更短
  • if-else:转换,生成的列表长度不变

5. 嵌套列表推导式

处理二维列表或嵌套结构:

# 二维列表展平
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# 方法1:先外层后内层
flat = [num for row in matrix for num in row]
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 等价的传统写法
flat = []
for row in matrix:
    for num in row:
        flat.append(num)

# 生成九九乘法表
table = [f"{i}×{j}={i*j}" for i in range(1, 10) for j in range(1, i+1)]
print(table[:5])  # ['1×1=1', '2×1=2', '2×2=4', '3×1=3', '3×2=6']

6. 其他推导式

Python 还有字典推导式、集合推导式:

字典推导式

{键表达式: 值表达式 for 变量 in 序列}
# 创建字典
numbers = range(1, 6)
squares_dict = {n: n ** 2 for n in numbers}
print(squares_dict)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 交换字典键值
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 = {name: score for name, score in scores.items() if score >= 80}
print(passed)  # {'Alice': 85, 'Bob': 92, 'David': 95}

集合推导式

{表达式 for 变量 in 序列}
# 去重并转换
numbers = [1, 1, 2, 2, 3, 3]
unique_squares = {n ** 2 for n in numbers}
print(unique_squares)  # {1, 4, 9}

# 提取首字母
words = ['apple', 'banana', 'apricot', 'blueberry', 'cherry']
first_letters = {w[0] for w in words}
print(first_letters)  # {'a', 'b', 'c'}

7. 生成器表达式

把方括号换成圆括号,就变成生成器:

# 列表推导式:立即生成所有元素
squares_list = [i ** 2 for i in range(10)]
print(type(squares_list))  # <class 'list'>

# 生成器表达式:惰性计算
squares_gen = (i ** 2 for i in range(10))
print(type(squares_gen))  # <class 'generator'>

# 需要时才计算
for sq in squares_gen:
    print(sq, end=' ')

区别

  • 列表推导式:内存中创建完整列表
  • 生成器表达式:按需生成,节省内存

大数据集用生成器更高效。

8. 实际应用

应用 1:数据清洗

# 清洗用户输入
inputs = ['  Alice  ', 'bob', '  Charlie\n']
cleaned = [name.strip().capitalize() for name in inputs]
print(cleaned)  # ['Alice', 'Bob', 'Charlie']

应用 2:文件处理

# 读取文件并处理(假设文件存在)
with open('data.txt') as f:
    numbers = [int(line.strip()) for line in f if line.strip().isdigit()]

应用 3:坐标变换

# 笛卡尔积
colors = ['红', '黑']
sizes = ['S', 'M', 'L']
products = [f"{color}-{size}" for color in colors for size in sizes]
print(products)
# ['红-S', '红-M', '红-L', '黑-S', '黑-M', '黑-L']

9. 注意事项

不要过度使用

虽然列表推导式很强大,但不要为了炫技而牺牲可读性:

# 可读性差(不推荐)
result = [[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]

# 应该拆分成多行或用传统循环

原则:如果列表推导式超过 2 行,或者逻辑复杂,就用传统 for 循环。

避免副作用

列表推导式应该是"纯函数",不要有副作用:

# 不好的例子
count = 0
result = [count := count + 1 for _ in range(5)]

# 应该用传统循环
count = 0
result = []
for _ in range(5):
    count += 1
    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 循环哪个性能更好?为什么?


本文代码示例


相关阅读