《Python AI 应用开发入门》第 2.6 节。
使用字典表示结构化聊天消息,使用集合完成去重和集合运算。
本节目标
学完本节后,你应当能够:
- 5. 根据“按名称查找”或“保留唯一值”的需求选择容器。
1. 为什么需要字典
列表可以保存一条消息:
message = ["user", "请解释字典", 1]
但只看值很难知道每个位置的含义。字典使用键给数据命名:
message = {
"role": "user",
"content": "请解释字典",
"sequence": 1,
}
字典保存键和值的映射。上例中:
键必须唯一;重复键只会保留后面的值。
2. 创建和读取字典
message = {
"role": "user",
"content": "请解释字典",
"sequence": 1,
}
print(message["role"])
print(message["content"])
print(len(message))
len() 返回键值对数量。
访问不存在的键会触发 KeyError:
# print(message["model"])
如果字段可能不存在,可以使用 get():
print(message.get("model"))
print(message.get("model", "尚未选择"))
找不到时,get() 默认返回 None,也可以提供默认值。
原则:
3. 新增和修改
语法相同:
message["model"] = "demo-mini" # 新增
message["content"] = "请举例解释字典" # 修改
使用 update() 一次更新多个字段:
message.update({
"model": "demo-pro",
"status": "completed",
})
如果键已存在就更新,不存在就新增。
4. 删除字段
message = {
"role": "user",
"content": "你好",
"temporary": True,
}
removed_value = message.pop("temporary")
print(removed_value)
键不存在时 pop() 会触发 KeyError,可以提供默认值:
removed_value = message.pop("missing", None)
清空全部字段:
message.clear()
5. 检查键和值
in 默认检查键:
message = {"role": "user", "content": "你好"}
print("role" in message) # True
print("user" in message) # False
print("user" in message.values()) # True
常见视图:
print(message.keys())
print(message.values())
print(message.items())
items() 中每一项是 (键, 值) 元组。下一节会使用循环逐项处理:
for key, value in message.items():
print(f"{key}: {value}")
这里先理解输出结构;循环语法会在第 2.7 节完整学习。
6. 嵌套数据
聊天历史通常是“列表中保存多个字典”:
messages = [
{
"role": "user",
"content": "什么是列表?",
},
{
"role": "assistant",
"content": "列表是有顺序的可变容器。",
},
]
读取第一条消息的内容:
print(messages[0]["content"])
读取最后一条消息的角色:
print(messages[-1]["role"])
新增一条消息:
new_message = {
"role": "user",
"content": "列表与元组有什么区别?",
}
messages.append(new_message)
这种结构与 Web API 中常见的 JSON 数据很接近。第 3 章会学习 JSON 文件读写。
7. 字典也是可变的
message = {"role": "user", "content": "你好"}
same_message = message
same_message["content"] = "已修改"
print(message["content"])
结果是“已修改”。两个变量指向同一字典。
需要复制这一层时:
message_copy = message.copy()
和列表一样,嵌套结构的浅复制不会自动复制内部的所有对象。
8. 什么是集合
集合是一组不重复、没有位置索引的值:
keywords = {"Python", "AI", "字典"}
集合适合:
创建空集合必须写:
keywords = set()
{} 创建的是空字典,不是空集合:
print(type({}))
print(type(set()))
9. 集合的增删与成员判断
keywords = {"Python", "AI"}
keywords.add("字典")
keywords.add("Python")
print(keywords)
重复添加 "Python" 不会产生第二份。
删除:
keywords.remove("AI")
keywords.discard("不存在的词")
remove() 找不到时触发 KeyError;discard() 找不到时不会报错。
成员判断:
print("Python" in keywords)
集合输出顺序不应被依赖。需要固定顺序显示时可以先排序:
print(sorted(keywords))
10. 用集合去重
tags = ["Python", "AI", "Python", "入门", "AI"]
unique_tags = set(tags)
print(unique_tags)
print(len(unique_tags))
这种方式不保证保留原顺序。如果需要按首次出现顺序去重,后续可以使用循环逐项处理。
文本关键词还需要先标准化,否则大小写不同会被视为不同值:
raw_tags = ["Python", "python", " PYTHON "]
normalized_tags = {
raw_tags[0].strip().lower(),
raw_tags[1].strip().lower(),
raw_tags[2].strip().lower(),
}
print(normalized_tags)
11. 集合运算
user_interests = {"Python", "RAG", "FastAPI"}
course_tags = {"Python", "AI", "FastAPI"}
交集:两边都有
print(user_interests & course_tags)
并集:合并全部唯一值
print(user_interests | course_tags)
差集:左边有、右边没有
print(user_interests - course_tags)
对称差集:只在一边出现
print(user_interests ^ course_tags)
这些运算很适合标签匹配、权限比较和关键词分析。
12. 四种容器如何选择
真实数据经常组合使用:
chat = {
"title": "Python 学习",
"participants": ("user", "assistant"),
"tags": {"Python", "基础"},
"messages": [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!"},
],
}
选择容器时先问:
动手练习
练习 1:结构化消息
创建 message_record.py:
- 4. 使用
get() 读取可选的 error 字段,默认显示“无错误”。
练习 2:聊天历史
创建一个包含三条消息的列表,每条消息都是字典。输出:
再追加一条新消息并更新总数。
练习 3:关键词集合
给定两组关键词:
question_tags = {"Python", "列表", "入门"}
course_tags = {"Python", "字典", "入门"}
输出共同关键词、全部关键词和只在问题中的关键词。
随堂小测
- 2.
message["model"] 与 message.get("model") 在键不存在时有什么区别? - 6.
remove() 和 discard() 删除不存在的集合元素时有什么区别?
参考答案
- 1. 键用于唯一定位对应的值;重复键无法同时表示两个映射,后面的值会覆盖前面的值。
- 2. 方括号触发
KeyError;get() 返回 None 或指定默认值。 - 4. 列表保留多条消息的顺序,字典用字段名清楚表示每条消息的结构。
- 6.
remove() 触发 KeyError,discard() 不报错。
本节完成检查