使用 dict 和 set
字典(dict)通过“键”查找“值”,适合表示具名字段和索引数据;集合(set)只保存不重复的元素,适合去重、成员判断和集合关系运算。
创建字典
student = {
"name": "小林",
"age": 18,
"score": 92,
}
empty_dict = {}
键必须是可哈希对象,最常用的是字符串和数字;同一个字典中键不能重复。Python 3.7+ 按插入顺序保留字典项目,但字典的主要用途仍是按键查找,不应把它当作列表按位置使用。
也可以用 dict() 或字典推导式创建:
student = dict(name="小林", age=18)
squares = {number: number * number for number in range(1, 4)}
print(squares) # {1: 1, 2: 4, 3: 9}
访问和修改
使用方括号访问键:
student = {"name": "小林", "score": 92}
print(student["name"])
student["score"] = 95 # 修改已有键
student["city"] = "上海" # 添加新键
访问不存在的键会抛出 KeyError。不确定键是否存在时,使用 get():
print(student.get("phone")) # None
print(student.get("phone", "未填写")) # 未填写
get() 的默认值只在键不存在时使用;如果键存在但值是 None,仍会返回 None。
安全地创建或更新
setdefault() 在键不存在时写入默认值,并返回最终值:
groups = {}
groups.setdefault("python", []).append("小林")
groups.setdefault("python", []).append("小周")
print(groups) # {'python': ['小林', '小周']}
批量合并字典可以使用 update():
base = {"theme": "light", "language": "zh"}
base.update({"theme": "dark", "font_size": 14})
print(base)
Python 3.9+ 还支持 | 合并和 |= 原地更新:
defaults = {"timeout": 10, "retries": 2}
custom = {"timeout": 30}
config = defaults | custom
右侧同名键会覆盖左侧值;嵌套字典不会自动深度合并。
删除字典项目
data = {"name": "小林", "age": 18, "city": "上海"}
city = data.pop("city") # 删除并返回值
age = data.pop("age", None) # 键不存在时返回默认值
last_key, last_value = data.popitem() # 删除并返回最后插入的项目
data.clear() # 清空
del data[key] 也可以删除项目,但键不存在时会抛出 KeyError。遍历字典时不要直接改变其大小:
data = {"a": 1, "b": 2, "c": 3}
for key in list(data):
if data[key] < 3:
del data[key]
遍历字典
student = {"name": "小林", "score": 95}
for key in student: # 默认遍历键
print(key)
for value in student.values():
print(value)
for key, value in student.items():
print(f"{key}:{value}")
判断键是否存在使用 in:
if "score" in student:
print(student["score"])
key in dictionary 检查键,不检查值;检查值应使用 value in dictionary.values()。
集合基础
集合使用大括号(至少有一个元素)或 set() 创建:
tags = {"python", "beginner", "python"}
print(tags) # 重复的 python 只保留一个
empty_set = set()
empty_dict = {}
集合无按位置访问的接口,元素顺序也不应作为业务依据。集合元素必须可哈希,因此列表、字典等可变对象不能直接放入集合。
常用操作:
tags.add("tutorial")
tags.update(["code", "learn"])
tags.discard("unknown") # 不存在也不报错
tags.remove("code") # 不存在时抛出 KeyError
使用 in 判断成员通常比在列表中搜索更适合大量查找:
blocked = {"bot", "spammer"}
if username in blocked:
print("拒绝访问")
集合运算
设有两个标签集合:
frontend = {"html", "css", "javascript"}
backend = {"python", "go", "javascript"}
print(frontend | backend) # 并集
print(frontend & backend) # 交集
print(frontend - backend) # 差集
print(frontend ^ backend) # 对称差集
对应的方法是 union()、intersection()、difference() 和 symmetric_difference()。还可以判断子集和超集:
required = {"html", "css"}
print(required <= frontend) # True,子集
print(frontend >= required) # True,超集
集合运算返回新集合;带 _update 后缀的方法(如 intersection_update())会原地修改集合。
字典和集合的可哈希键
字典键和集合元素需要稳定的哈希值。整数、字符串和元素也可哈希的元组通常可以使用;列表、字典和集合不可哈希:
locations = {(31.2, 121.5): "上海"}
print(locations[(31.2, 121.5)])
# {[1, 2]} # TypeError:list 不可哈希
# {"key": []} # 这里列表作为值可以,作为键不行
元组能否作为键取决于其中所有元素是否可哈希:(1, "a") 可以,(1, [2]) 不可以。
计数和分组
使用普通字典可以实现计数:
words = ["python", "go", "python", "dart"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts) # {'python': 2, 'go': 1, 'dart': 1}
标准库 collections.Counter 更适合计数:
from collections import Counter
counts = Counter(words)
print(counts.most_common(2))
分组时可以使用 setdefault(),或使用 collections.defaultdict:
from collections import defaultdict
groups = defaultdict(list)
for name, language in [("小林", "Python"), ("小周", "Python"), ("小王", "Go")]:
groups[language].append(name)
常见错误
data["missing"]和data.get("missing")的行为不同:前者报错,后者返回默认值。set()的输出顺序不固定,不要用set表示需要排序或按位置访问的数据。- 通过
dict.fromkeys(keys, [])创建嵌套列表会共享同一个列表;需要独立列表时使用字典推导式。 - 字典和集合的“键/元素”必须可哈希;需要以列表内容作为键时,可先转换为元组。
- 浅复制字典不会复制嵌套的列表或字典,必要时使用
copy.deepcopy()或明确复制内层数据。
综合示例:找出共同选修课程
alice = {"Python", "数据库", "英语"}
bob = {"Go", "数据库", "英语"}
common = alice & bob
all_courses = alice | bob
print(f"共同课程:{'、'.join(sorted(common))}")
print(f"全部课程数量:{len(all_courses)}")
集合负责去重和关系运算,sorted() 只在展示时提供稳定顺序。
练习
- 使用字典保存商品名称和库存,完成一次购买后更新库存,并处理商品不存在的情况。
- 统计一段文本中每个单词的出现次数,忽略大小写。
- 给定两个用户兴趣集合,求共同兴趣和只属于第一个用户的兴趣。
- 将学生按班级分组,输出每个班级的人数。
- 设计一个字典缓存函数结果,命中缓存时直接返回,未命中时计算并保存。
小结
dict通过键查找值,set保存不重复元素;两者都适合快速成员判断。get()安全读取,setdefault()可按需初始化,update()和|可合并字典。- 字典遍历使用
keys()、values()、items();判断键存在直接使用in。 - 集合支持并集、交集、差集和对称差集,顺序不应作为集合数据的语义。
- 字典键和集合元素必须可哈希;可变容器不能直接作为键或集合元素。