9·模块二:控制流与循环入门

列表、字典与集合推导式

comprehensionlist-comprehension

第 9 课 - 列表、字典与集合推导式

课程:Python 编程:从零基础到精通 模块:模块二:控制流与循环 难度:beginner 标签:comprehension, list-comprehension 上一课:For 循环与迭代器 下一课:函数定义与调用

学习目标

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

  1. 理解并熟练使用列表推导式,用简洁的一行代码创建列表。
  2. 掌握字典推导式的语法,快速从可迭代对象生成字典。
  3. 了解集合推导式,用于创建无重复元素的集合。
  4. 对比传统循环与推导式,理解推导式在代码简洁性与可读性上的平衡。
  5. 识别并避免初学者在使用推导式时的常见错误。

核心概念

想象一下,你有一堆原材料(比如数字1到10),想把它们加工成一组产品(比如它们的平方数)。用传统 for 循环,你需要"一步步走":准备好空列表 -> 逐个加工 -> 添加到列表里。推导式就像是一个高效的"自动化生产线",你只需在一条生产指令里描述好"原材料"和"加工规则",就能直接得到成品列表。

列表推导式

这是最常用的推导式。它的基本结构是:

[表达式 for 变量 in 可迭代对象 if 条件]
  • 表达式:就是对每个元素进行的"加工规则"(如 x**2)。
  • for 变量 in 可迭代对象:定义了原材料从哪里来(如 for x in range(10))。
  • if 条件(可选):用于筛选,只有满足条件的元素才会被加工。

字典推导式

用于创建字典,结构类似列表推导式,但用花括号 {},且表达式是 键:值 对。

{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}

集合推导式

与列表推导式几乎一样,只是用花括号 {},并且结果会自动去除重复元素。

{表达式 for 变量 in 可迭代对象 if 条件}

代码示例

# ===== 1. 列表推导式 vs 传统循环 =====
# 任务:创建一个包含1到10所有平方数的列表

# 方法一:传统 for 循环
squares_loop = []
for x in range(1, 11): # 生成1到10
    squares_loop.append(x ** 2)
print("循环法得到的平方数列表:", squares_loop)

# 方法二:列表推导式(一行搞定!)
squares_comp = [x ** 2 for x in range(1, 11)]
print("推导式得到的平方数列表:", squares_comp)
# 输出完全相同: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

print("-" * 30)

# ===== 2. 带条件的列表推导式 =====
# 任务:从1到20中,只挑选偶数,并计算它们的平方
even_squares = [x**2 for x in range(1, 21) if x % 2 == 0] # `if x % 2 == 0` 就是筛选条件
print("1-20中偶数的平方:", even_squares)
# 输出: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

print("-" * 30)

# ===== 3. 字典推导式 =====
# 任务:创建一个字典,键是数字1-5,值是它的立方
cubes_dict = {num: num**3 for num in range(1, 6)}
print("数字-立方字典:", cubes_dict)
# 输出: {1: 1, 2: 8, 3: 27, 4: 64, 5: 125}

# 任务:颠倒原有字典的键值对
original = {'a': 1, 'b': 2, 'c': 3}
reversed_dict = {value: key for key, value in original.items()}
print("颠倒后的字典:", reversed_dict)
# 输出: {1: 'a', 2: 'b', 3: 'c'}

print("-" * 30)

# ===== 4. 集合推导式 =====
# 任务:从一个包含重复元素的列表中,得到所有不重复元素的平方集合
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 5]
unique_squares = {x**2 for x in numbers} # 自动去重
print("不重复元素的平方集合:", unique_squares)
# 输出: {16, 1, 4, 9, 25} (集合元素顺序不固定)

print("-" * 30)

# ===== 5. 复杂一点的例子:嵌套循环在推导式中 =====
# 任务:生成一个列表,包含所有两个元组(a, b)的和,其中a来自[1,2],b来自[10,20,30]
sums = [a + b for a in [1, 2] for b in [10, 20, 30]]
print("两层循环的推导式结果:", sums)
# 输出: [11, 21, 31, 12, 22, 32]

实践练习

练习 1 (入门)

使用列表推导式,生成一个包含数字 0 到 9 中所有奇数的列表。 预期输出: [1, 3, 5, 7, 9]

练习 2 (进阶)

有一个句子 "Hello Python World, Hello List Comprehension",请使用列表推导式,提取句子中所有长度大于 4 的单词,并将它们转换为大写后放入一个新列表。 提示:先用 .split() 方法将句子拆分为单词列表。 预期输出: ['HELLO', 'PYTHON', 'WORLD,', 'HELLO', 'COMPREHENSION']

练习 3 (挑战)

使用字典推导式,从下面两个列表创建一个字典,其中 keys 中的元素是键,values 中对应的元素是值。

keys = ['name', 'age', 'city']
values = ['Alice', 25, 'New York']

然后,再用一个字典推导式,将上一步得到的字典中所有字符串类型的值转换为小写(即 'New York' 变为 'new york')。 预期输出: 第一步字典: {'name': 'Alice', 'age': 25, 'city': 'New York'} 第二步字典: {'name': 'alice', 'age': 25, 'city': 'new york'}

常见错误

  1. 括号混淆:列表推导式用 [],字典和集合推导式用 {}。写错会导致语法错误或生成错误的数据类型。

    # 错误示例
    wrong_list = {x: x*2 for x in range(3)} # 这其实是字典推导式,得到 {0:0, 1:2, 2:4}
    wrong_dict = [key: value for key, value in {'a':1}.items()] # 语法错误
    
  2. 滥用推导式,导致可读性差:推导式虽简洁,但如果逻辑太复杂(如多层嵌套、多个条件),应该拆分成传统的 for 循环,保持代码清晰。

    # 难以阅读的推导式(不推荐)
    messy = [x*y for x in range(5) if x>2 for y in [10,20] if y<15]
    # 改写为循环会更清晰
    clear = []
    for x in range(5):
        if x > 2:
            for y in [10, 20]:
                if y < 15:
                    clear.append(x*y)
    
  3. 忘记 for 前面的"表达式":推导式的核心是 表达式 for ...。如果只想简单地筛选元素而不变换,表达式就是变量本身。

    # 正确:筛选偶数
    evens = [x for x in range(10) if x % 2 == 0]
    # 错误:缺少表达式
    # wrong = [for x in range(10) if x % 2 == 0]
    
  4. 变量作用域混淆:在推导式中定义的循环变量(如 for x in ... 中的 x)在推导式执行完毕后,依然会在当前作用域中存在(在Python 3中)。但这不是最佳实践,应避免在推导式外依赖这个变量。

小结

  • 列表推导式 [x for x in iterable] 是快速创建列表的"语法糖",比循环更简洁。
  • 字典推导式 {k: v for ...} 是生成字典的利器,尤其适合转换现有数据结构。
  • 集合推导式 {x for ...} 在创建不重复集合时非常方便。
  • 推导式中可以包含 if 条件语句,用于筛选元素。
  • 使用推导式时,要在代码简洁性可读性之间取得平衡。当逻辑复杂时,传统的 for 循环可能是更好的选择。

掌握了推导式,你的Python代码会变得更加"Pythonic"(符合Python风格),编程效率也会大大提升!

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「函数定义与调用」 以巩固所学知识。