4.2 字典
目标
- 掌握 dict 的增删改查,区分
d[k](缺键抛错)与d.get(k)(缺键返回默认值)。 - 用
items()/keys()/values()遍历;知道 dict 保持插入顺序。 - 读懂并写出嵌套结构的访问路径(JSON 风格数据)。
- 认识 dict 作为配置表、分发表的用法。
核心概念
创建与访问
字典是“键 → 值”映射。键必须是可哈希的(str、int 等不可变类型;tuple 仅当其元素都可哈希时才可哈希),值任意。
Python · 可运行
python
config = {"base_url": None, "key_env": "DEEPSEEK_API_KEY", "model": "deepseek-flash"}
print(config["model"]) # 取值;键不存在抛 KeyError
print(config.get("timeout")) # 键不存在返回 None
print(config.get("timeout", 30)) # 指定默认值
print("model" in config, len(config)) # in 判断的是键
config["max_tokens"] = 1024 # 新增或覆盖
del config["base_url"] # 删除
removed = config.pop("key_env") # 删除并返回值
print(config, removed)
d2 = dict(model="m", max_tokens=10) # 关键字参数构造
print(d2)遍历
dict 按插入顺序迭代(3.7 起成为语言保证)。直接遍历得到键;items() 同时得到键和值。
Python · 可运行
python
PROVIDERS = {
"deepseek": {"model": "deepseek-flash"},
"anthropic": {"model": "claude-haiku-4-5"},
}
for name in PROVIDERS:
print(name)
for name, cfg in PROVIDERS.items():
print(f"{name} → {cfg['model']}")
print(list(PROVIDERS.keys()), list(PROVIDERS.values()))合并与更新
Python · 可运行
python
defaults = {"max_tokens": 1024, "temperature": 1.0}
overrides = {"temperature": 0}
merged = defaults | overrides # 3.9 起:返回新字典,右侧优先
also = {**defaults, **overrides} # 等价的旧写法
print(merged, merged == also)
defaults.update(overrides) # 原地更新
print(defaults)setdefault 与计数分组
Python · 可运行
python
groups = {}
for block_type in ["text", "tool_use", "text"]:
groups.setdefault(block_type, 0) # 键不存在才设置,返回当前值
groups[block_type] += 1
print(groups)
counts = {}
for t in ["text", "tool_use", "text"]:
counts[t] = counts.get(t, 0) + 1 # 另一种常见写法
print(counts)8.5 会介绍更专业的 collections.Counter 与 defaultdict。
嵌套结构与访问路径
API 数据多是 dict 与 list 的嵌套(和 JSON 一一对应)。读码时,从外到内逐层写出类型:
Python · 可运行
python
tools = [
{
"name": "get_weather",
"description": "查询城市天气",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}
]
# tools → list;tools[0] → dict;["input_schema"] → dict;["properties"] → dict;["city"] → dict;["type"] → str
print(tools[0]["input_schema"]["properties"]["city"]["type"])
print(tools[0]["input_schema"]["required"][0])
print(list(tools[0]["input_schema"]["properties"]))易错点
d[k]缺键抛KeyError:不确定键是否存在时用d.get(k)或先if k in d。但“必须存在”的配置用d[k]更好——缺了立即报错,而不是带着None继续运行。- 遍历时增删键:抛
RuntimeError: dictionary changed size during iteration;遍历list(d)副本。 - 用可变对象做键:
{[1, 2]: "x"}抛TypeError: unhashable type: 'list';改用 tuple。 in判断的是键不是值:"deepseek-flash" in config为False,判断值用in config.values()。
Python · 可运行演示报错
python
PROVIDERS = {"deepseek": {}, "anthropic": {}}
provider = "openai"
config = PROVIDERS[provider]对照
| 操作 | Python dict | JS 对象 / Map | Java HashMap |
|---|---|---|---|
| 字面量 | {"a": 1}(键要加引号) | {a: 1} | Map.of("a", 1) |
| 取值 | d["a"](缺键抛错)/ d.get("a") | o.a / o["a"](缺键 undefined) | m.get("a")(缺键 null) |
| 属性式访问 | 不支持 d.a | 支持 | — |
| 判断键 | "a" in d | "a" in o / m.has("a") | m.containsKey("a") |
| 遍历键值 | for k, v in d.items() | Object.entries(o) | m.entrySet() |
| 合并 | d1 | d2 / {**d1, **d2} | {...o1, ...o2} | putAll |
| 顺序 | 插入顺序 | 基本为插入顺序 | 无序(LinkedHashMap 有序) |
注意:Python dict 不能用 d.key 访问;resp.content、block.type 能用点号,是因为它们是对象(类实例),不是 dict(见阶段 7)。
读代码
python
PROVIDERS = {
"deepseek": {"base_url": "https://api.deepseek.com/anthropic", "key_env": "DEEPSEEK_API_KEY", "model": "deepseek-flash"},
"anthropic": {"base_url": None, "key_env": "ANTHROPIC_API_KEY", "model": "claude-haiku-4-5"},
}
config = PROVIDERS[provider] # 第一层:按服务名取出配置 dict
api_key = os.getenv(config["key_env"]) # 第二层:取出“环境变量名”,再读环境变量
TOOL_FUNCTIONS = {"get_weather": get_weather} # 分发表:工具名 → 函数PROVIDERS[provider]用下标而不是get:LLM_PROVIDER写错时立即抛KeyError,比带着None跑到后面报一个看不懂的错更好。- 两层 dict 的读法:外层键选“哪一个”,内层键选“哪个字段”。
练习
练习 1:访问路径
给定下面的 tools,写出三个表达式并赋值:first_name(第一个工具名)、city_type(get_weather 的 city 参数类型)、required(get_weather 的必填参数列表)。
练习
tools = [
{"name": "get_weather", "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}},
{"name": "get_time", "input_schema": {"type": "object", "properties": {}, "required": []}},
]
first_name = None
city_type = None
required = None
快捷键:⌘/Ctrl + Enter 提交检查
练习 2:解析配置
实现 resolve_config(providers, env):env 是模拟环境变量的 dict。规则与 minimal_agent.py 一致:
provider = env.get("LLM_PROVIDER") or "deepseek",用下标取providers[provider](不存在就让它抛KeyError);model = env.get("LLM_MODEL") or 配置中的 model;api_key = env.get(配置中的 key_env)。
返回 (provider, model, api_key)。
练习
def resolve_config(providers, env):
...
快捷键:⌘/Ctrl + Enter 提交检查
练习 3:按类型计数
实现 count_types(blocks):blocks 是 dict 列表,返回 {类型: 数量},键的顺序为首次出现的顺序。
练习
def count_types(blocks):
counts = {}
return counts
快捷键:⌘/Ctrl + Enter 提交检查
小结
d[k]缺键抛KeyError,d.get(k, 默认)安全取值;必需的配置用下标更好。- 遍历键值用
items();dict 保持插入顺序。 - 合并用
|或{**a, **b},右侧优先。 - 嵌套数据逐层写出类型,就能写出访问路径。