🐍 元组与集合 — 列表的两个"亲戚"
🕐 预计用时:2-3 小时 | 🎯 今日目标:掌握元组的不可变性,掌握集合的去重和运算
📖 今日目录
1. 元组(Tuple):不可修改的列表
📦 什么是元组?
元组就是"只读列表"——创建后不能修改。
生活比喻:列表像一个可擦写的白板(随时改),元组像一张打印好的表格(改不了)。
🔧 创建元组
# 直接创建point = (3, 4)colors = ("红", "绿", "蓝")mixed = (1, "hello", 3.14, True)# 单元素元组(注意逗号!)single = (42,) # ✅ 这是元组not_tuple = (42) # ❌ 这是整数,括号只是运算优先级print(type(single)) # <class 'tuple'>print(type(not_tuple)) # <class 'int'># 不加括号也行(自动识别为元组)auto = 1, 2, 3print(type(auto)) # <class 'tuple'>
⚠️ 单元素元组必须加逗号!(42) = 整数 42(括号只是改变优先级) (42,) = 只有一个元素的元组 记忆:逗号才是元组的标志,不是括号。
2. 元组常用操作
📍 访问(和列表一样)
colors = ("红", "橙", "黄", "绿", "蓝")print(colors[0]) # 红print(colors[-1]) # 蓝print(colors[1:3]) # ('橙', '黄')print(colors[::-1]) # ('蓝', '绿', '黄', '橙', '红') 反转
🔗 元组运算
# 拼接a = (1, 2, 3)b = (4, 5, 6)c = a + bprint(c) # (1, 2, 3, 4, 5, 6)# 重复d = ("Ha",) * 3print(d) # ('Ha', 'Ha', 'Ha')# 成员判断print(2 in a) # Trueprint(7 in a) # False# 长度、最大、最小print(len(a)) # 3print(max(a)) # 3print(min(a)) # 1
🔄 解包(Unpacking)
# 变量解包point = (3, 4)x, y = pointprint(x) # 3print(y) # 4# 交换变量(Python 的优雅写法)a = 10b = 20a, b = b, a # 右边先打包成元组,再解包赋给左边print(a, b) # 20 10# 星号解包first, *rest = (1, 2, 3, 4, 5)print(first) # 1print(rest) # [2, 3, 4, 5] — 注意:星号拿到的是列表
❌ 为什么需要元组?
# 1. 安全性:数据不会被意外修改SETTINGS = ("localhost", 8080, "/api")# SETTINGS[0] = "0.0.0.0" # ❌ TypeError,防止误改配置# 2. 性能:元组比列表快,占用内存少import syslst = [1, 2, 3, 4, 5]tpl = (1, 2, 3, 4, 5)print(sys.getsizeof(lst)) # 120(列表更大)print(sys.getsizeof(tpl)) # 80(元组更小)# 3. 可作字典的键(列表不行,因为列表可变)# 后面讲字典时会用到
📋 元组常用方法
| | |
|---|
count(x) | | (1,2,1,1).count(1) |
index(x) | | (10,20,30).index(20) |
元组只有这两个方法——因为不能修改,所以没有 append/remove/sort 等方法。
3. 集合(Set):自动去重的容器
📦 什么是集合?
集合是 Python 的"去重神器"——里面的元素不重复,且无序。
生活比喻:
🔧 创建集合
# 直接创建(用花括号)fruits = {"苹果", "香蕉", "橘子"}print(fruits) # {'橘子', '香蕉', '苹果'} — 顺序可能不同!# 自动去重nums = {1, 2, 2, 3, 3, 3}print(nums) # {1, 2, 3} — 重复的自动去掉# 用 set() 创建(从列表去重)names = ["张三", "李四", "张三", "王五", "李四"]unique = set(names)print(unique) # {'张三', '李四', '王五'}# 空集合(不能用 {},那是空字典!)empty_set = set() # ✅ 空集合# empty = {} # ❌ 这是空字典!
⚠️ 空集合必须用 set(),不能用 {}!{} = 空字典(后面会学) set() = 空集合 这是 Python 的一个历史包袱。
➕ 添加和删除
s = {1, 2, 3}# 添加单个s.add(4)print(s) # {1, 2, 3, 4}# 添加已存在的元素(没效果,也不报错)s.add(2)print(s) # {1, 2, 3, 4} — 没变# 删除指定元素s.remove(3) # 不存在会报错 KeyErrorprint(s) # {1, 2, 4}s.discard(99) # 不存在也不报错(推荐用这个)print(s) # {1, 2, 4} — 没变# 随机删除并返回一个元素popped = s.pop()print(popped) # 随机一个print(s) # 剩下的# 清空s.clear()print(s) # set()
4. 集合运算:交集、并集、差集
集合最强大的地方在于数学运算——用一行代码代替多行循环。
a = {1, 2, 3, 4, 5}b = {4, 5, 6, 7, 8}
🔗 交集(共同拥有的)
# 两种写法print(a & b) # {4, 5}print(a.intersection(b)) # {4, 5}# 应用:找两个班的共同学生class_a = {"张三", "李四", "王五", "赵六"}class_b = {"李四", "赵六", "孙七", "周八"}both = class_a & class_bprint("两班都有的学生:", both) # {'李四', '赵六'}
➕ 并集(合在一起去重)
print(a | b) # {1, 2, 3, 4, 5, 6, 7, 8}print(a.union(b)) # {1, 2, 3, 4, 5, 6, 7, 8}# 应用:合并两个名单vip = {"张三", "李四"}new_vip = {"王五", "李四"}all_vip = vip | new_vipprint("所有VIP:", all_vip) # {'张三', '李四', '王五'}
➖ 差集(A有B没有的)
print(a - b) # {1, 2, 3} — 在a中但不在b中print(a.difference(b)) # {1, 2, 3}print(b - a) # {6, 7, 8} — 在b中但不在a中(顺序很重要!)# 应用:找出流失用户all_users = {"张三", "李四", "王五", "赵六"}active = {"张三", "王五"}churned = all_users - activeprint("流失用户:", churned) # {'李四', '赵六'}
⊕ 对称差集(各自独有,去掉共同的)
print(a ^ b) # {1, 2, 3, 6, 7, 8}print(a.symmetric_difference(b)) # {1, 2, 3, 6, 7, 8}
🔍 判断关系
a = {1, 2, 3}b = {1, 2, 3, 4, 5}c = {6, 7, 8}# 子集print(a.issubset(b)) # True — a 是 b 的子集print(a <= b) # True(等价写法)# 超集print(b.issuperset(a)) # True — b 是 a 的超集print(b >= a) # True# 不相交print(a.isdisjoint(c)) # True — a 和 c 没有交集
📊 集合运算速查表
| | | |
|---|
| a & b | a.intersection(b) | |
| a | b | a.union(b) | |
| a - b | a.difference(b) | |
| a ^ b | a.symmetric_difference(b) | |
| a <= b | a.issubset(b) | |
| a >= b | a.issuperset(b) | |
5. frozenset:不可变集合
就像元组是"不可变的列表",frozenset 是"不可变的集合"。
fs = frozenset([1, 2, 3])print(fs) # frozenset({1, 2, 3})# fs.add(4) # ❌ AttributeError# fs.remove(2) # ❌ AttributeError# 可以做集合运算(返回新的 frozenset)fs2 = frozenset([3, 4, 5])print(fs & fs2) # frozenset({3}) — 交集print(fs | fs2) # frozenset({1, 2, 3, 4, 5}) — 并集
💡 什么时候用 frozenset? 当你需要一个"不能修改的集合",比如用作字典的键(字典的键必须不可变)。
6. 实战项目
🏋️ 实战 1:名单对比工具
print("=== 名单对比工具 ===")# 输入两组名单print("输入第一组名单(用逗号分隔):")list1 = set(input().split(","))print("输入第二组名单(用逗号分隔):")list2 = set(input().split(","))# 去除空格list1 = {name.strip() for name in list1}list2 = {name.strip() for name in list2}print(f"\n第一组:{list1}")print(f"第二组:{list2}")print(f"共同成员:{list1 & list2}")print(f"只在第一组:{list1 - list2}")print(f"只在第二组:{list2 - list1}")print(f"所有人(去重):{list1 | list2}")
🏋️ 实战 2:简易投票系统
voters = set() # 已投票的人results = {} # 候选人得票print("=== 投票系统 ===")print("输入 'end' 结束投票")while True: name = input("\n请输入您的姓名:") if name == "end": break if name in voters: print("❌ 您已经投过票了!") continue print("候选人:张三、李四、王五") candidate = input("投票给谁?") if candidate in ["张三", "李四", "王五"]: voters.add(name) results[candidate] = results.get(candidate, 0) + 1 print(f"✅ 投票成功!已投票人数:{len(voters)}") else: print("❌ 无效候选人")print("\n=== 投票结果 ===")for candidate, votes in sorted(results.items(), key=lambda x: x[1], reverse=True): print(f"{candidate}:{votes} 票")print(f"总投票人数:{len(voters)}")
🏋️ 练习题
练习 1:创建一个元组 (1,2,3,4,5),尝试修改它,观察报错信息。
练习 2:输入一个字符串,用集合找出里面有多少个不同的字符。
练习 3:给定两个列表 [1,2,2,3,4,4,5] 和 [4,5,5,6,7,7,8],用集合运算求:交集、并集、差集。
练习 4:写一个程序,输入一段英文文本,用集合统计其中有多少个不同的单词(不区分大小写)。
7. 今日小结
| |
|---|
| 不可修改的列表,用 () 创建,单元素要加逗号 (1,) |
| x, y = (3, 4) |
| 无序、自动去重,用 {} 创建,空集合用 set() |
| & |
| |
| |
🧠 自检清单
⬜ 知道元组和列表的区别
⬜ 知道单元素元组必须加逗号
⬜ 能用集合去重和做集合运算
⬜ 知道空集合用 set() 而不是 {}
⭐ 能用集合解决实际的"找共同""找差异"问题
🎯 Day 10 预告
明天学习字典(Dict)——Python 最强大的数据结构,用"键-值对"存储数据。
就像一本真正的字典:查"苹果"就能得到"apple"。📖
📅 Day 9 完成!你已经认识了 Python 的四大容器:列表、元组、集合,明天的字典会让它们全部串起来。明天见! 🚀