在 Python 中,列表(list)、元组(tuple)、字典(dict)和集合(set)都是可迭代对象(Iterable),遍历的核心机制是for...in循环,但根据它们底层数据结构的差异(序列、映射、哈希表),遍历方式各有特色。
下面我为你由浅入深地详细梳理,并特别针对集合(Set)进行深度扩展。
一、遍历列表(List)与元组(Tuple)
列表和元组都是有序序列,遍历方式完全通用(元组不可变,但遍历语法一致)。
1. 直接遍历元素(最常用)
直接取出容器内的每个元素。
lst=['a','b','c']foriteminlst:print(item)# 输出: a, b, c2. 通过索引遍历(range+ 长度)
适用于需要修改元素值或需要知道元素位置下标时。
foriinrange(len(lst)):print(f"索引{i}:{lst[i]}")3. 同时获取索引和元素(enumerate)——Pythonic 推荐
省去手动维护下标的麻烦,效率高且优雅。
forindex,valueinenumerate(lst):print(f"第{index}个元素是{value}")# 可以自定义起始序号forindex,valueinenumerate(lst,start=1):print(f"第{index}个元素是{value}")4. 反向遍历(reversed)
不修改原列表,生成反向迭代器。
foriteminreversed(lst):print(item)# 输出: c, b, a5. 并行遍历多个序列(zip)
同时拉取多个列表的对应位置元素。
names=['A','B']scores=[90,85]forname,scoreinzip(names,scores):print(f"{name}:{score}")6. 使用while循环(通用,但不推荐用于单纯遍历)
底层通过下标控制,适合复杂退出条件,但书写繁琐。
i=0whilei<len(lst):print(lst[i])i+=1二、遍历字典(Dict)
字典是键值对(Key-Value)映射结构,Python 3.7+ 保证插入顺序。
1. 直接遍历(默认遍历键keys())
d={'name':'Tom','age':18}forkeyind:print(key)# 输出: name, age# 等价于 for key in d.keys():2. 遍历值(values())
只关心数据,不关心标签。
forvalueind.values():print(value)# 输出: Tom, 183. 同时遍历键和值(items())——最常用
解包元组,直接获取完整数据。
forkey,valueind.items():print(f"{key}->{value}")4. 遍历字典时修改内容(需转换为列表)
重点:遍历过程中直接修改字典大小(增删)会报RuntimeError。解决办法是把视图转为列表再遍历。
# 错误示范:for k in d: del d[k] # 报错!# 正确做法:forkinlist(d.keys()):ifk=='age':deld[k]三、遍历集合(Set)—— 基础篇
集合是无序(严格说是有序但开发者不可依赖)、元素唯一的哈希表。
1. 标准for循环遍历元素
s={1,2,3,'a'}foritemins:print(item)# 每次运行顺序可能不同(如 a, 1, 2, 3)2. 使用enumerate获取人为序号
由于集合无序,“索引”在此处仅代表遍历到第几个元素,不代表物理位置。
foridx,iteminenumerate(s):print(f"第{idx}个取出的元素是:{item}")3. 使用迭代器(iter和next)
底层实现,通常用于手动精细控制。
it=iter(s)whileTrue:try:item=next(it)print(item)exceptStopIteration:break4. 集合推导式(Comprehension)
本质上也是一种遍历并生成新集合的语法糖。
new_set={x*2forxinsifisinstance(x,int)}注意:集合不支持索引访问(如
s[0]),也不支持切片,因此无法通过range(len(s))的方式按位置遍历。
四、深入详解 Python 中的集合(Set)
既然你要“详细介绍”,我把集合从底层原理到实战细节彻底展开。
1. 核心特性
- 无序性:基于哈希表(Hash Table)实现,元素存放位置由哈希值决定,不维护插入顺序(虽然 CPython 3.6 后实现上保留了插入顺序,但官方文档不保证,请勿依赖)。
- 唯一性:自动去重,任何两个相等的元素(
==)只会保留一个。 - 元素必须可哈希(Hashable):不可变类型(int, str, tuple)可以放入;可变类型(list, dict, set)不能放入,否则报
TypeError: unhashable type。
2. 创建集合的坑
a={}# 这是空字典,不是集合!b=set()# 这是正确的空集合c={1,2,3}# 非空集合3. 增删改查(核心方法)
| 方法 | 作用 | 注意事项 |
|---|---|---|
add(elem) | 添加元素 | 如果已存在,则无效果 |
update(iterable) | 合并另一个可迭代对象(批量加) | 相当于 ` |
remove(elem) | 删除元素 | 元素不存在会报错(KeyError) |
discard(elem) | 删除元素 | 元素不存在也不会报错(推荐) |
pop() | 随机弹出一个元素 | 空集合调用会报错 |
clear() | 清空集合 | - |
4. 集合数学运算(高频考点)
这是集合相比其他数据结构最强大的功能,性能极高(基于哈希碰撞检测)。
| 运算 | 操作符 | 方法名 | 含义 |
|---|---|---|---|
| 并集 | | | union() | 两者加起来的所有元素 |
| 交集 | & | intersection() | 两者共有的元素 |
| 差集 | - | difference() | 在 A 但不在 B 中的元素 |
| 对称差集 | ^ | symmetric_difference() | 只属于其中一个集合的元素(剔除共有) |
| 子集/超集 | <=/>= | issubset()/issuperset() | 判断包含关系 |
| 是否不相交 | - | isdisjoint() | 没有交集返回 True |
A={1,2,3}B={3,4,5}print(A-B)# {1, 2}print(A&B)# {3}print(A^B)# {1, 2, 4, 5}5. 巨大的性能优势 —— 成员检测
- 列表(List):
if x in list时间复杂度O(n)(遍历查找)。 - 集合(Set):
if x in set时间复杂度O(1)(哈希直接命中)。
实战建议:如果需要频繁判断某个元素是否存在,务必先将列表转为集合再判断。
6. 不可变集合 ——frozenset
既然集合不能包含集合(因为可变),但业务上可能需要嵌套结构。frozenset是集合的不可变版本,可以作为字典的键或另一个集合的元素。
fs=frozenset([1,2,3])d={fs:"value"}# 合法7. 遍历集合时修改集合(同样不安全)
和字典一样,遍历中修改集合大小会报错。解决方案:遍历其副本。
s={1,2,3,4}foriteminlist(s):# 转换为列表副本ifitem%2==0:s.remove(item)print(s)# {1, 3}总结对比(快速记忆)
| 数据结构 | 遍历常用方式 | 是否有序 | 是否允许重复 | 能否索引 |
|---|---|---|---|---|
| 列表 | for item in list,enumerate | ✅ | ✅ | ✅ |
| 元组 | 同上 | ✅ | ✅ | ✅ |
| 字典 | for k,v in dict.items() | ✅ (3.7+) | 键唯一,值随意 | 按键名dict[key] |
| 集合 | for item in set | ❌ (不可依赖) | ❌ (自动去重) | ❌ (哈希表无序) |
最后送给你一条 Python 之禅:“Flat is better than nested.”遍历时优先使用for...in直接解包,少用range(len()),代码会更具可读性。