# 第 1-10 课:字典 ## 一、本课目标 完成本课后,你应该能够: 1. 解释键值对是什么; 2. 创建字典和空字典; 3. 使用键读取字典中的值; 4. 使用 `get()` 安全读取数据; 5. 添加和修改键值对; 6. 使用 `pop()`、`del` 和 `clear()` 删除数据; 7. 使用 `keys()`、`values()` 和 `items()`; 8. 遍历字典的键、值和键值对; 9. 使用嵌套字典表达分组配置; 10. 使用列表保存多个字典记录; 11. 理解字典键的基本限制; 12. 判断列表、元组和字典的适用场景。 ## 二、前置知识 开始本课前,你应该已经掌握: - 字符串、数字和布尔值; - 列表与元组; - `if` 条件判断; - `for` 循环; - `in` 成员判断; - f-string 格式化输出。 ## 三、为什么需要字典 上一课可以使用元组保存 Agent 配置: ```python agent_config = ("gpt-5", 0.7, 2000, True) ``` 读取配置时依赖固定位置: ```python model_name = agent_config[0] temperature = agent_config[1] ``` 代码阅读者必须记住每个位置的含义。 字典(Dictionary,类型名为 `dict`)使用名称描述每一项数据: ```python agent_config = { "model": "gpt-5", "temperature": 0.7, "max_tokens": 2000, "enabled": True, } ``` 读取时直接使用字段名称: ```python print(agent_config["model"]) print(agent_config["temperature"]) ``` 这种代码更容易理解,也适合表达配置、用户、产品和接口数据。 ## 四、键值对 字典中的每一项由键和值组成,称为键值对(Key-Value Pair): ```python "model": "gpt-5" ``` - 键(Key):`"model"`,用于定位数据; - 值(Value):`"gpt-5"`,是真正保存的数据。 键和值之间使用英文冒号 `:`,多个键值对之间使用英文逗号分隔。 ## 五、创建字典 ### 5.1 创建包含数据的字典 ```python agent_config = { "model": "gpt-5", "temperature": 0.7, "max_tokens": 2000, "enabled": True, } ``` 多行字典的最后一个键值对后保留逗号,是常见的代码风格,便于以后增加字段和查看 Git 差异。 ### 5.2 创建空字典 ```python empty_config = {} ``` 也可以写成: ```python empty_config = dict() ``` 初学阶段优先使用 `{}`。 ### 5.3 查看类型与长度 ```python print(type(agent_config)) print(len(agent_config)) ``` `len()` 返回键值对数量。 ## 六、使用方括号读取值 ```python model_name = agent_config["model"] ``` 方括号中写的是键,不是数字位置。 如果键不存在: ```text agent_config["timeout"] ``` 会产生 `KeyError`,中文可以理解为“指定键不存在”。 适用场景:确定该键必须存在,缺少时应当暴露错误。 ## 七、使用 `get()` 安全读取 ```python timeout = agent_config.get("timeout") ``` 键不存在时,默认返回 `None`,不会产生 `KeyError`。 `None` 表示“没有值”或“空值”,它是 Python 中一个特殊对象,不是字符串 `"None"`。 可以设置默认值: ```python timeout = agent_config.get("timeout", 30) ``` 如果 `timeout` 不存在,返回整数 `30`。 需要注意:`get()` 返回默认值不会自动把这个键写入字典。 ## 八、判断键是否存在 `in` 用于判断字典中是否存在指定键: ```python if "model" in agent_config: print(agent_config["model"]) ``` 判断不存在: ```python if "timeout" not in agent_config: print("尚未配置超时时间") ``` 默认情况下,`in` 检查的是键,不是值: ```python print("model" in agent_config) # True print("gpt-5" in agent_config) # False ``` ## 九、添加和修改键值对 字典是可变对象,可以添加和修改数据。 ### 9.1 添加新键 ```python agent_config["timeout"] = 30 ``` 如果键原来不存在,就会新增。 ### 9.2 修改已有键 ```python agent_config["temperature"] = 0.3 ``` 如果键已经存在,就会覆盖旧值。 相同语法会根据键是否存在决定“新增”还是“修改”。 ## 十、使用 `update()` 更新多个字段 ```python agent_config.update({ "temperature": 0.2, "timeout": 60, }) ``` `update()` 会: - 修改已存在的键; - 添加不存在的键。 它直接修改原字典,通常不返回更新后的字典。 ## 十一、删除键值对 ### 11.1 `pop()` 删除并返回值 ```python removed_timeout = agent_config.pop("timeout") ``` 键不存在时会产生 `KeyError`。可以提供默认值: ```python removed_timeout = agent_config.pop("timeout", None) ``` 这样键不存在时返回 `None`。 ### 11.2 `del` 删除指定键 ```python if "timeout" in agent_config: del agent_config["timeout"] ``` `del` 不返回被删除的值。 ### 11.3 `clear()` 清空字典 ```python agent_config.clear() ``` 字典变量仍然存在,但键值对数量变为 `0`。 ## 十二、获取键、值和键值对 ### 12.1 `keys()` ```python config_keys = agent_config.keys() ``` 得到所有键。 ### 12.2 `values()` ```python config_values = agent_config.values() ``` 得到所有值。 ### 12.3 `items()` ```python config_items = agent_config.items() ``` 得到所有键值对。遍历字典时最常用。 这些方法返回的是字典视图(Dictionary View),不是普通列表。现阶段可以直接遍历;确实需要列表时,可以使用 `list()` 转换。 ## 十三、遍历字典 ### 13.1 遍历键 ```python for key in agent_config: print(key) ``` 也可以明确写成: ```python for key in agent_config.keys(): print(key) ``` ### 13.2 遍历值 ```python for value in agent_config.values(): print(value) ``` ### 13.3 同时遍历键和值 ```python for key, value in agent_config.items(): print(f"{key}:{value}") ``` `items()` 每次提供一个包含键和值的二元素元组,再通过元组解包分别交给 `key` 和 `value`。 ## 十四、字典是否有顺序 现代 Python 字典会保留键值对的插入顺序。 ```python config = { "model": "gpt-5", "temperature": 0.7, "enabled": True, } ``` 遍历时通常按照写入顺序得到这些键。 但是字典的核心用途仍然是“通过键查找值”,不应依赖数字索引访问。字典不支持: ```text config[0] ``` 除非数字 `0` 本身就是一个真实的键。 ## 十五、字典键必须唯一 一个字典中不能同时存在两个相同的键: ```python config = { "model": "gpt-5", "model": "o3", } ``` 后面的值会覆盖前面的值,最终 `model` 是 `"o3"`。 因此,字典不能依靠重复键保存多条同名记录。 ## 十六、什么数据可以作为键 字典键必须是可哈希(Hashable)的对象。初学阶段可以记住:常见不可变类型通常可以作为键。 常见可用键: - 字符串; - 整数; - 浮点数; - 布尔值; - 只包含不可变元素的元组。 列表不能作为键: ```text invalid_dict = {["Python", "FastAPI"]: "工具"} ``` 会产生 `TypeError`,因为列表可变。 实际业务中最常用字符串键,含义清晰,也方便与 JSON 和接口数据对应。 ## 十七、嵌套字典 字典的值可以是另一个字典: ```python agent_config = { "model": { "name": "gpt-5", "temperature": 0.7, }, "runtime": { "timeout": 30, "enabled": True, }, } ``` 读取嵌套值: ```python model_name = agent_config["model"]["name"] timeout = agent_config["runtime"]["timeout"] ``` 第一组方括号取得内部字典,第二组方括号从内部字典读取数据。 嵌套层级过深会降低可读性。真实项目应根据业务结构合理分组。 ## 十八、列表中保存字典 如果要保存多个 Agent,可以使用列表存放多个字典: ```python agents = [ {"name": "代码助手", "model": "gpt-5", "enabled": True}, {"name": "搜索助手", "model": "o3", "enabled": False}, ] ``` 遍历: ```python for agent in agents: print(f"{agent['name']}:{agent['model']}") ``` 可以理解为: - 列表负责保存多条记录; - 每个字典负责描述一条记录的字段。 这种结构在接口返回的 JSON 数据中非常常见。 ## 十九、字典中保存列表 字典的值也可以是列表: ```python agent = { "name": "代码助手", "tools": ["搜索", "计算", "写作"], } ``` 添加一个工具: ```python agent["tools"].append("代码执行") ``` 这里先读取 `tools` 对应的列表,再调用列表的 `append()`。 ## 二十、字典复制 直接赋值不会创建独立字典: ```python original_config = {"model": "gpt-5"} alias_config = original_config alias_config["model"] = "o3" ``` 两个变量会看到同一个修改结果。 简单字典可以使用 `copy()`: ```python copied_config = original_config.copy() copied_config["model"] = "o3" ``` 这仍然是浅复制。字典内部如果包含列表或字典,内部对象仍可能共享。深复制属于进阶内容。 ## 二十一、列表、元组和字典如何选择 ### 列表 适合保存多个同类、有顺序、数量可能变化的数据: ```python tools = ["搜索", "计算", "写作"] ``` ### 元组 适合保存固定结构、创建后不希望变化的数据: ```python position = (116.4, 39.9) ``` ### 字典 适合保存带字段名称的数据: ```python agent = {"name": "代码助手", "model": "gpt-5"} ``` 真实程序通常会组合使用三种结构。 ## 二十二、运行本课示例 在 PowerShell 中执行: ```powershell cd D:\Code\Python\01_python基础\1_10_字典 python dictionaries.py ``` 示例无需用户输入,会展示字典的创建、读取、增删改查、遍历、嵌套和复制。 ## 二十三、常见错误 ### 23.1 使用不存在的键 确定键不一定存在时,可以使用 `get()` 或先使用 `in` 判断。 ### 23.2 误以为 `in` 检查值 默认情况下,`in` 检查的是键。 ### 23.3 字典键重复 相同键只能保留一个值,后面的值会覆盖前面的值。 ### 23.4 使用列表作为键 列表可变,不能作为字典键。 ### 23.5 遍历时直接修改字典大小 遍历字典期间直接添加或删除键,可能产生运行错误。需要修改结构时,可以先记录目标,循环结束后再修改。 ### 23.6 直接赋值误认为复制 `backup = original` 不会创建独立字典。 ## 二十四、课堂练习 打开 `practice.py`,完成“Agent 配置管理器”。 运行命令: ```powershell python practice.py ``` 练习会要求你创建配置、读取默认值、修改字段、删除字段、遍历数据,并处理嵌套字典和 Agent 列表。 ## 二十五、思考题 1. 字典与元组相比,读取配置时有什么优势? 2. 方括号读取与 `get()` 有什么区别? 3. `in` 默认判断字典的键还是值? 4. 为什么字典键必须唯一? 5. 为什么列表不能作为字典键? 6. `items()` 遍历时为什么可以使用两个变量? 7. 列表中保存字典适合表达什么数据? ## 二十六、本课小结 - 字典使用键值对保存数据; - 键用于定位数据,值是真正保存的内容; - 方括号适合读取必须存在的键; - `get()` 可以安全读取并提供默认值; - 字典是可变对象,可以增删改键值对; - `keys()`、`values()`、`items()` 提供不同遍历方式; - 键必须唯一且可哈希; - 字典可以嵌套,也可以与列表组合; - 字段明确的数据通常适合使用字典。 ## 二十七、验收标准 - [ ] 能创建字典和空字典; - [ ] 能使用方括号和 `get()` 读取值; - [ ] 能安全添加、修改和删除键值对; - [ ] 能判断键是否存在; - [ ] 能遍历键、值和键值对; - [ ] 能使用嵌套字典; - [ ] 能使用列表保存多个字典; - [ ] 能解释常见字典键限制; - [ ] 能完成并运行 `practice.py`; - [ ] 能回答七道思考题。