Python: 容器对比与全能推导式

前几课我们把列表、元组、字典、集合一个个学完了。这一课来做个横向对比——它们到底有什么不同?什么时候该用哪个?同时把推导式这个 Python 神器彻底讲透。


1. 四大容器对比

特性 列表 (list) 元组 (tuple) 字典 (dict) 集合 (set)
符号 [] () {key: value} {}set()
有序 ✅ 有顺序 ✅ 有顺序 ✅ 插入顺序(3.7+) ❌ 无序
可变
可重复 键唯一、值可重复 ❌ 元素唯一
访问方式 索引 [0] 索引 [0] ["key"] 不支持索引
查找速度 O(n) 慢 O(n) 慢 O(1) 极快 O(1) 极快
典型用途 有序数据、动态集合 固定数据、函数返回值 映射关系、缓存 去重、集合运算
💡 关键选型原则: 1)需要按位置取 → 列表/元组;2)需要按名字取 → 字典;3)需要去重或数学运算 → 集合;4)数据不该变 → 元组。

▶ 示例:容器选型对比(难度⭐⭐)

PYTHON
# 同一个场景用不同容器实现

# 场景:存储学生姓名
# 用列表——有顺序,方便增删
students_list = ["Alice", "Bob", "Charlie"]
students_list.append("赵六")
print(f"列表:{students_list[0]}")    # Alice

# 用元组——固定不变(比如班级花名册)
students_tuple = ("Alice", "Bob", "Charlie")
# students_tuple[0] = "xxx"     # 报错!元组不可修改
print(f"元组:{students_tuple[0]}")   # Alice

# 用字典——按学号快速查找
students_dict = {
    "001": "Alice",
    "002": "Bob",
    "003": "Charlie",
}
print(f"字典:{students_dict['002']}")  # Bob——O(1) 速度

# 用集合——去重(比如签到名单)
attendance = {"Alice", "Bob", "Charlie", "Alice"}
print(f"集合:{attendance}")            # {'Bob', 'Charlie', 'Alice'}——重复的Alice被去重
▶ 试一试

输出:

TEXT 📖 仅展示
# 执行成功


2. 列表推导式强化

第 11 课学了基础推导式,这里深入更多技巧。

(1) 多条件过滤

PYTHON
numbers = range(1, 31)

# 能被 3 整除且能被 5 整除
filtered = [n for n in numbers if n % 3 == 0 and n % 5 == 0]
print(filtered)             # [15, 30]

# 能被 3 整除或能被 5 整除
filtered = [n for n in numbers if n % 3 == 0 or n % 5 == 0]
print(filtered)             # [3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30]

(2) 嵌套循环推导式

PYTHON
# 生成坐标对——相当于双重 for 循环
pairs = [(x, y) for x in range(3) for y in range(3)]
print(pairs)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

# 带条件的嵌套——找出所有两数之和为偶数的组合
pairs = [(x, y) for x in range(3) for y in range(3) if (x + y) % 2 == 0]
print(pairs)
# [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)]

(3) if-else 在推导式中

PYTHON
# if-else 在推导式中的写法——注意位置不同
numbers = [1, 2, 3, 4, 5, 6]

# 只有 if(过滤)——写在后面
evens = [n for n in numbers if n % 2 == 0]

# if-else(变换)——写在前面
result = ["偶数" if n % 2 == 0 else "奇数" for n in numbers]
print(result)   # ['奇数', '偶数', '奇数', '偶数', '奇数', '偶数']

▶ 示例:数据转换流水线(难度⭐⭐⭐)

PYTHON
# 一行代码完成:筛选→转换→格式化
raw = ["  apple  ", "BANANA", "", "  CHERRY", None, "  date  "]

# 过滤掉 None 和空字符串 → 去掉空白 → 首字母大写
cleaned = [item.strip().capitalize() for item in raw if item and item.strip()]
print(cleaned)              # ['Apple', 'Banana', 'Cherry', 'Date']
▶ 试一试

运行结果:

TEXT 📖 仅展示
['Apple', 'Banana', 'Cherry', 'Date']


3. 字典推导式

字典也可以推导,语法和列表推导式类似,只是用 {} 并指定键值对:

PYTHON
# 基本字典推导式
squares = {x: x ** 2 for x in range(5)}
print(squares)              # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# 带条件
even_squares = {x: x ** 2 for x in range(10) if x % 2 == 0}
print(even_squares)         # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

# 反转字典的键和值
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'}

(1) 实用场景:列表转字典

PYTHON
# 两个列表合并成字典
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
result = {names[i]: scores[i] for i in range(len(names))}
print(result)               # {'Alice': 85, 'Bob': 92, 'Charlie': 78}

# 用 zip() 更优雅
result = {name: score for name, score in zip(names, scores)}
print(result)               # {'Alice': 85, 'Bob': 92, 'Charlie': 78}


4. 集合推导式

集合推导式用 {} 但只有表达式没有冒号——和字典的区别在于有没有冒号:

PYTHON
# 集合推导式——自动去重
numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares)       # {1, 4, 9, 16, 25}

# 带条件
even_set = {x for x in range(20) if x % 2 == 0}
print(even_set)             # {0, 2, 4, 6, 8, 10, 12, 14, 16, 18}
💡 三者的区别: [x for x in ...] 是列表 → 有序、可重复。{x: y for x in ...} 是字典 → 有冒号。{x for x in ...} 是集合 → 无冒号、无序、去重。

▶ 示例:词语分析(难度⭐⭐⭐)

PYTHON
# 分析一篇文章的词汇
article = """
Python is great. Python is powerful!
I love Python. JavaScript is also great.
But Python is my favorite.
"""

# 提取所有单词
words = article.lower().split()

# 用集合推导式去重
unique_words = {word.strip(".!,") for word in words}
print(f"总词数:{len(words)}")
print(f"不重复词数:{len(unique_words)}")
print(f"所有不重复词:{sorted(unique_words)}")
▶ 试一试

运行结果:

TEXT 📖 仅展示
总词数:18
不重复词数:10
所有不重复词:['also', 'but', 'favorite', 'great', 'is', 'javascript', 'love', 'my', 'python', 'i']


5. 常见应用场景


❓ 常见问题

Q 列表推导式和生成器表达式有什么区别?
A 列表推导式 [x for x in range(10)] 一次性生成全部数据存在内存中。生成器表达式 (x for x in range(10)) 是惰性的——用到一个才生成一个,省内存。数据量大时(几万条以上)用生成器。
Q 推导式嵌套超过两层怎么办?
A 超过两层的推导式可读性急剧下降。[x for xs in matrix for ys in xs for x in ys] 这种代码几乎没人能一眼看懂。如果逻辑需要三层以上,拆成普通 for 循环或者先写几个辅助函数。
Q 怎么判断一个数据该用哪个容器?
A 三步法:① 是否需要唯一键?→ 是则字典。② 是否需要去重或集合运算?→ 是则集合。③ 数据需要修改吗?→ 是则列表,否则元组。大多数场景下,列表和字典覆盖了 90% 的需求。

📖 小节


📝 作业

  1. 基础题(难度⭐):用列表推导式生成 10 到 50 之间所有能被 7 整除或包含数字 7 的数字。提示:用 or 连接两个条件。

  2. 进阶题(难度⭐⭐):给定两个列表 keys = ["name", "age", "city"]values = ["Alice", 25, "北京"],用字典推导式把它们合并成一个字典。提示:用 zip(keys, values) 配对。

  3. 挑战题(难度⭐⭐⭐):写一个"数据统计器"。给定一个包含多个句子的字符串,统计并输出:

    • 总单词数
    • 不重复单词数
    • 出现频率最高的 3 个单词
    • 提示:用 split() 分词、字典计数、sorted(dict.items(), key=lambda x: x[1], reverse=True)[:3] 取前三。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏