字典(Dict):键值对、遍历、常用方法
一句话概述
字典(Dict)是 Python 中最强大的数据结构——它不是按数字位置索引,而是按**自定义的"键"(key)**来存取数据。就像现实中的字典:你要查"Apple"的意思,不需要翻遍全书找到第 637 页——直接按字母顺序找到 "Apple" 词条,一秒查到释义。Python 字典底层使用哈希表实现,查找速度极快(O(1)),无论字典多大,找到某个键的时间几乎恒定。在 AI 开发中,字典用于存储词表映射、模型配置、缓存计算结果、JSON 数据解析等各种场景。
💡 核心要点:①字典是键值对(key-value)的无序(Python 3.7+ 有序)映射容器 ②键必须是不可变类型(字符串、数字、元组),值可以是任何类型 ③通过键访问值:d[key],用get()安全访问避免 KeyError ④遍历字典有keys()、values()、items()三种方式 ⑤字典推导式一行代码构建字典,是数据处理利器
教学与演示
一、字典的创建与本质——从查词典说起
是什么:字典(dict)是 Python 的映射类型(Mapping),用花括号 {} 或 dict() 构造函数创建。每个元素是一个键值对(key-value pair):键(key)是查找的"索引词条",值(value)是该词条对应的"解释内容"。键必须是不可变且可哈希的类型(字符串、数字、元组等),值可以是任意类型。
大白话 如果把列表比作一排编了号的储物柜(按 0、1、2... 找),字典就是贴了标签的储物柜——每个柜子贴了自定义的标签(键),你喊一声"取苹果",直接打开贴"苹果"标签的柜子,不用管它在第几排第几列。而且 Python 的字典比储物柜厉害——它几乎瞬间就能找到你想找的键,哪怕字典里有成百上千个键值对。
为什么:字典解决了列表无法解决的"按名称访问"问题。如果你想存储"Alice 是 25 岁,Bob 是 30 岁",用列表得记 Alice 是第 0 个、Bob 是第 1 个——数据一多就乱套。用字典 {"Alice": 25, "Bob": 30},直接用名字查年龄。字典 O(1) 的查找速度是它的杀手锏——在 AI 中,词表可能有数十万条,在列表中查找一个词是 O(n)(要遍历),在字典中是 O(1)(哈希直达)。
大白话 没有字典的世界:你想查某人的手机号,得从通讯录第一页翻到最后一页。有字典的世界:直接在搜索框输入名字,0.1 秒出结果。Python 字典的哈希表就是这样——给每个键算一个"门牌号",直接定位,不用遍历。
怎么做:
import numpy as np
# ====== 1. 创建字典的四种方式 ======
# 方式一:直接用花括号(最常用)
person = {
"name": "张三", # 键是字符串,冒号分隔,逗号结尾
"age": 25, # 值可以是整数
"city": "北京", # 不同类型混搭
"is_student": True # 布尔值
}
print("人员信息:", person)
# 方式二:dict() 构造函数,关键字参数
person2 = dict(name="李四", age=30, city="上海")
print("人员信息2:", person2)
# 方式三:从键值对序列创建
pairs = [("name", "王五"), ("age", 22), ("city", "深圳")]
person3 = dict(pairs) # 把 (键, 值) 元组列表转成字典
print("人员信息3:", person3)
# 方式四:fromkeys() 批量创建相同默认值的字典
keys = ["语文", "数学", "英语"] # 科目列表作为键
scores = dict.fromkeys(keys, 0) # 所有值初始化为 0
print("初始成绩:", scores) # {'语文': 0, '数学': 0, '英语': 0}
# ====== 2. 字典的键的要求 ======
# ✅ 合法的键:字符串、数字、元组
valid = {
"name": "字符串键",
42: "数字键",
(1, 2): "元组键", # 元组不可变,可以做键
3.14: "浮点数键",
True: "布尔键" # 注意:True 会被当作 1 处理!
}
print("\n合法键:", valid)
# ❌ 列表不能做键(因为列表可变、不可哈希)
# d = {[1, 2]: "value"} ❌ TypeError: unhashable type: 'list'
# ====== 3. 访问与修改值 ======
scores = {"语文": 85, "数学": 92, "英语": 78}
print("\n成绩:", scores)
# 通过键访问值
print("数学成绩:", scores["数学"]) # 92
# 修改值
scores["语文"] = 90 # 语文改分
print("修改语文后:", scores)
# 添加新键值对
scores["物理"] = 88 # 直接赋值不存在的键 = 添加
print("添加物理后:", scores)
# 删除键值对
del scores["英语"] # del 关键字删除
print("删除英语后:", scores)
# ====== 4. 使用 get() 安全访问(避免 KeyError) ======
# 直接访问不存在的键会报错
try:
print(scores["化学"]) # KeyError: '化学'
except KeyError:
print("\n'化学' 不存在于字典中,直接访问会报错")
# get(key, default):键存在返回对应值,不存在返回默认值(不报错!)
print("化学成绩:", scores.get("化学", "未考试")) # '未考试'
print("物理成绩:", scores.get("物理", "未考试")) # 88
# ====== 5. 字典的成员检查:in 运算符 ======
print("\n=== 成员检查 ===")
print("'数学' 在字典中:", '数学' in scores) # True — 检查键是否存在
print("'化学' 在字典中:", '化学' in scores) # False
print("92 在字典中:", 92 in scores) # False — in 只检查键,不检查值!
print("92 在值中:", 92 in scores.values()) # True — 要用 .values() 检查值什么用:字典在 AI 中无处不在。词表映射(word-to-index):{"猫": 0, "狗": 1, "鸟": 2} 把文本转成数字;标签映射(label-to-name):{0: "猫", 1: "狗"} 把数字转回文字;模型配置:{"lr": 0.001, "epochs": 100};缓存计算结果:{input_hash: output} 避免重复计算。字典是连接"人类可读"和"机器可算"的桥梁。
二、字典的遍历——三种方式查遍所有键值对
是什么:字典的遍历通过三种视图对象实现——keys() 遍历所有键,values() 遍历所有值,items() 遍历键值对。最常用的是 items(),配合解包语法 for k, v in d.items() 同时获取键和值。
大白话 遍历字典就像翻阅一本词典。keys()只看词条(不看释义),values()只看释义(不看词条),items()一个词条+一个释义成对看。大多时候你用items()——就像看书时既要知道"Apple"这个词(键),又要知道"苹果"(值)。
为什么:遍历是数据处理中最常用的操作——统计所有键/值、过滤符合条件的条目、批量转换格式。理解三种遍历方式的区别和性能特点,能让你在处理大规模数据(如几十万条词表)时写出既清晰又高效的代码。
大白话 如果你只想检查字典里有没有某个关键词,用keys()就够了——不用把值也加载出来。如果你只关心所有成绩的总和,用values()就够了——不用管对应的科目名。Python 让你按需获取,不多浪费一点内存。
怎么做:
import numpy as np
# ====== 1. 遍历键:d.keys() ======
# 模拟:产品库存字典
inventory = {
"苹果": 50, "香蕉": 30, "橘子": 80,
"西瓜": 15, "葡萄": 45
}
print("=== 遍历键 ===")
print("所有产品名:")
for key in inventory.keys(): # 遍历所有键
print(f" - {key}") # 苹果、香蕉、橘子...
# 更简洁:for key in inventory: (默认遍历键)
print("\n(更简洁写法)所有产品名:")
for key in inventory: # 默认就是遍历键!
print(f" - {key}")
# ====== 2. 遍历值:d.values() ======
print("\n=== 遍历值 ===")
total = 0
for count in inventory.values(): # 遍历所有库存量
total += count
print(f"总库存: {total}") # 220
# 找出库存不足的产品(值 < 30)
print("库存不足的产品(<30):")
for name, count in inventory.items(): # 用 items 同时拿键和值
if count < 30: # 库存小于 30
print(f" {name}: 仅剩 {count} 个,需要补货!")
# ====== 3. 遍历键值对:d.items() ——最常用! ======
print("\n=== 遍历键值对 ===")
# items() 返回 (键, 值) 元组,配合解包使用
for product, quantity in inventory.items(): # 解包:product=键, quantity=值
status = "充足" if quantity >= 50 else "一般" if quantity >= 30 else "紧张"
print(f" {product}: {quantity} 个 → {status}")
# ====== 4. AI 实战:遍历词表映射 ======
# 词 → 索引 映射(NLP 中的基础数据结构)
word_to_idx = {
"<PAD>": 0, "<UNK>": 1, # 特殊标记:填充词、未知词
"猫": 2, "狗": 3, "鸟": 4,
"鱼": 5, "喜欢": 6, "吃": 7,
}
print(f"\n词表大小: {len(word_to_idx)} 个词")
# 反向映射:索引 → 词
idx_to_word = {} # 创建空字典
for word, idx in word_to_idx.items(): # 遍历词表
idx_to_word[idx] = word # 把键值对反过来
print("索引→词:", idx_to_word)
# 模拟:把一句话转成索引序列
sentence = ["猫", "喜欢", "吃", "鱼"]
encoded = []
for word in sentence:
# 用 get 安全查找——未知词用 <UNK> 的索引(1)
idx = word_to_idx.get(word, word_to_idx["<UNK>"])
encoded.append(idx)
print(f"\n原始句子: {sentence}")
print(f"编码后: {encoded}") # [2, 6, 7, 5]
# 模拟:把索引序列转回文字
decoded = [idx_to_word[i] for i in encoded] # 列表推导式解码
print(f"解码后: {decoded}")
# ====== 5. 排序遍历 ======
print("\n=== 按库存量排序展示 ===")
# sorted() + items() + key 参数按值排序
sorted_items = sorted(inventory.items(),
key=lambda x: x[1], # x 是 (键, 值) 元组,按值(库存量)排序
reverse=True) # 降序:库存多的在前
for product, qty in sorted_items:
# 用 f-string 对齐输出
print(f" {product:4s}: {'█' * (qty // 5)} {qty}") # 柱状图效果什么用:在 AI 数据预处理中,字典遍历是极其高频的操作。构建词表时遍历语料库用 d.keys() 检查新词;统计词频时遍历 d.items() 计算 TF-IDF;模型推理后将索引序列解码回文字时遍历 idx_to_word。PyTorch 的 state_dict(模型参数字典)遍历 model.state_dict().items() 查看每一层的参数名和形状。
三、常用方法——字典自带的高效工具箱
是什么:字典拥有一套完善的内置方法,涵盖增删改查、合并、默认值处理等常见场景。这些方法大多经过 C 语言优化,比手写逻辑快得多。理解每个方法的适用场景和行为,能让你在处理字典时如鱼得水。
大白话 字典的方法就像一个专业的图书管理员——pop按书名找到并抽出那本书,update把另一堆书合并进来(重名的覆盖旧的),setdefault是"看看有没有这本书,没有我就补一本放进去"。每个方法都有特定的职责,用对了事半功倍。
为什么:在处理复杂数据时,手写循环和条件判断不仅代码冗长,还容易出错。字典的内置方法帮你把常见模式(如"键存在就返回、不存在就设置默认值")封装成一行调用。在 AI 流水线中,这些方法让配置管理、特征映射、结果聚合变得异常简洁。
怎么做:
import numpy as np
# ====== 1. 添加与更新:update() ======
config = {"lr": 0.01, "epochs": 50}
print("原始配置:", config)
# update() 合并另一个字典(键相同则覆盖)
config.update({"lr": 0.001, "batch_size": 32}) # lr 被覆盖,batch_size 新增
print("更新后:", config) # {'lr': 0.001, 'epochs': 50, 'batch_size': 32}
# update() 也接受关键字参数
config.update(optimizer="Adam", dropout=0.5)
print("再次更新:", config)
# ====== 2. 删除:pop()、popitem()、clear() ======
data = {"a": 1, "b": 2, "c": 3, "d": 4}
print(f"\n原始: {data}")
# pop(key, default):删除键并返回值(键不存在且无默认值时报错)
val = data.pop("a") # 删除 'a',返回 1
print(f"pop('a')→{val}, 剩余: {data}")
val = data.pop("z", "没找到") # 键不存在,返回默认值,不报错
print(f"pop('z', '没找到')→{val}")
# popitem():删除并返回最后一个键值对(Python 3.7+ 是最后插入的)
key, val = data.popitem() # 删除 ('d', 4)
print(f"popitem()→({key}, {val}), 剩余: {data}")
# clear():清空字典
data.clear()
print(f"clear() 后: {data}") # {}
# ====== 3. 获取与默认值:get()、setdefault() ======
word_count = {"hello": 5, "world": 3}
print(f"\n词频: {word_count}")
# get():安全获取,键不存在返回默认值
print("get('hello'):", word_count.get("hello", 0)) # 5
print("get('python'):", word_count.get("python", 0)) # 0
# setdefault():键存在返回对应值;不存在则设置默认值并返回
# 这是统计词频的经典写法!
text = "apple banana apple orange banana apple"
freq = {} # 空字典
for word in text.split(): # 按空格分拆单词
freq[word] = freq.get(word, 0) + 1 # 方法一:get() 经典写法
# 等价于:freq.setdefault(word, 0); freq[word] += 1 # 方法二
print(f"\n词频统计: {freq}")
# ====== 4. 视图对象:keys()、values()、items() ======
d = {"x": 10, "y": 20}
keys_view = d.keys() # 返回动态视图(不是静态列表!)
print(f"\n初始键视图: {list(keys_view)}") # ['x', 'y']
# 修改字典后,视图自动反映变化!
d["z"] = 30 # 添加新键
print(f"添加 'z' 后: {list(keys_view)}") # ['x', 'y', 'z'] — 视图自动更新了!
# ====== 5. 字典推导式——一行创建字典 ======
# 这是 Python 的强大特性,在 AI 数据处理中极其常用
# 把列表变成 {元素: 索引} 的映射
fruits = ["苹果", "香蕉", "橘子", "西瓜"]
fruit_idx = {fruit: i for i, fruit in enumerate(fruits)}
print(f"\n水果→索引: {fruit_idx}")
# 过滤:只保留库存≥100的
stock = {"A": 150, "B": 80, "C": 200, "D": 50}
high_stock = {k: v for k, v in stock.items() if v >= 100}
print(f"高库存产品: {high_stock}")
# 变换:所有值平方
scores = {"Alice": 85, "Bob": 92, "Charlie": 78}
squared = {name: score ** 2 for name, score in scores.items()}
print(f"分数平方: {squared}")
# ====== 6. AI 实战:用字典缓存计算结果 ======
# 模拟:费时计算的模型推理,用字典做缓存
# 实际中这种技巧叫 memoization(记忆化)
cache = {} # 缓存字典
compute_count = 0 # 统计实际计算次数
def expensive_compute(x):
"""模拟一个耗时计算(实际中可能是模型推理)"""
global compute_count
if x in cache: # 如果已经算过
return cache[x] # 直接返回缓存结果(瞬间完成)
compute_count += 1
result = x ** 2 + np.sin(x) * 10 # 模拟复杂计算
cache[x] = result # 存入缓存
return result
# 多次调用,观察缓存效果
inputs = [1, 2, 3, 1, 2, 4, 3, 1]
results = []
for x in inputs:
results.append(round(expensive_compute(x), 4))
print(f"\n输入序列: {inputs}")
print(f"输出结果: {results}")
print(f"实际计算次数: {compute_count}") # 只算了 4 次(1,2,3,4)
print(f"缓存命中: {len(inputs) - compute_count} 次") # 4 次直接从缓存返回
print(f"缓存内容: {cache}")什么用:字典方法在 AI 开发中频繁出现。update() 用于合并多个超参数配置源(命令行参数覆盖默认配置);get() 在词表查询中安全处理未知词;setdefault() 构建邻接矩阵、统计共现频率;字典推导式用于数据格式转换(如 DataFrame 的 .to_dict());缓存(memoization)模式在模型推理服务中用于避免重复计算相同输入的结果,提升服务吞吐量。
四、嵌套字典与复杂结构——管理多维数据
是什么:字典的值可以是任何类型——包括另一个字典。嵌套字典形成了树状的层次结构,非常适合表达有层级关系的数据(如 JSON 数据、模型架构配置、多层特征映射)。通过链式的 [] 访问(如 d["layer1"]["weights"]),可以深入到任意深度的数据。
大白话 嵌套字典就像文件夹系统。根目录下有子文件夹,子文件夹里还能再有子文件夹。d["home"]["user"]["documents"]就像cd /home/user/documents一样逐层深入。JSON 格式就是按照这个思路设计的——整个互联网的 API 数据交换都用它。
为什么:真实世界的数据很少是平面的。一个用户的地址包含省、市、街道,一个神经网络的配置包含每层的学习率、激活函数、dropout 率,一个数据集的元信息包含字段名、类型、缺失率。嵌套字典自然地表达了这种层次结构,远比维护多个独立字典再手动关联要清晰。
怎么做:
import numpy as np
# ====== 1. 嵌套字典的创建与访问 ======
# 模拟:用户信息数据库(嵌套结构)
users = {
"user_001": { # 用户ID作为键
"name": "张三",
"age": 25,
"address": { # 第二层嵌套:地址信息
"country": "中国",
"city": "北京",
"district": "海淀区"
},
"courses": ["Python", "机器学习"], # 值也可以是列表
},
"user_002": {
"name": "李四",
"age": 30,
"address": {
"country": "中国",
"city": "上海",
"district": "浦东新区"
},
"courses": ["深度学习", "计算机视觉"],
}
}
# 访问嵌套数据:逐层索引
print("张三的城市:", users["user_001"]["address"]["city"]) # 北京
print("李四的课程:", users["user_002"]["courses"]) # ['深度学习', '计算机视觉']
# ====== 2. 遍历嵌套字典 ======
print("\n=== 所有用户信息 ===")
for user_id, info in users.items(): # 第一层循环:用户ID → 用户信息
name = info["name"]
city = info["address"]["city"]
course_count = len(info["courses"])
print(f" {user_id}: {name}, {city}, 在读{course_count}门课")
# ====== 3. 安全访问嵌套字典 ======
# 链式 get() 安全访问:任何中间层不存在都不报错
district = (users.get("user_001", {})
.get("address", {})
.get("district", "未知"))
print(f"\n安全获取 user_001 的区: {district}")
# 获取不存在的用户
district = (users.get("user_999", {})
.get("address", {})
.get("district", "未知"))
print(f"安全获取 user_999 的区: {district}") # 不报错,返回默认值
# ====== 4. 嵌套字典的修改 ======
# 添加新字段
users["user_001"]["phone"] = "13800138000"
print(f"\n添加号码后 user_001: {users['user_001']}")
# 深层修改
users["user_001"]["address"]["district"] = "朝阳区"
print(f"搬家后: {users['user_001']['address']['district']}") # 朝阳区
# ====== 5. AI 实战:模型架构的嵌套配置 ======
# 模拟一个简单的神经网络配置
model_config = {
"model_name": "SimpleCNN",
"input_shape": (28, 28, 1), # 输入图像尺寸(高、宽、通道)
"layers": { # 各层配置
"conv1": {
"type": "Conv2D",
"filters": 32,
"kernel_size": (3, 3),
"activation": "relu"
},
"pool1": {
"type": "MaxPooling",
"pool_size": (2, 2)
},
"conv2": {
"type": "Conv2D",
"filters": 64,
"kernel_size": (3, 3),
"activation": "relu"
},
"dense": {
"type": "Dense",
"units": 128,
"activation": "relu"
},
"output": {
"type": "Dense",
"units": 10, # 10 个类别
"activation": "softmax"
}
},
"compile": { # 编译配置
"optimizer": "adam",
"loss": "categorical_crossentropy",
"metrics": ["accuracy"]
}
}
print("\n=== 模型架构配置 ===")
print(f"模型名: {model_config['model_name']}")
print(f"输入尺寸: {model_config['input_shape']}")
# 统计总参数量
total_filters = 0
for layer_name, layer_cfg in model_config["layers"].items():
if layer_cfg.get("type") == "Conv2D": # 只统计卷积层
total_filters += layer_cfg["filters"]
print(f" {layer_name}: {layer_cfg['filters']} 个滤波器")
print(f"总滤波器数: {total_filters}")
# 遍历编译选项
print(f"\n编译配置:")
for key, val in model_config["compile"].items():
print(f" {key}: {val}")什么用:嵌套字典是处理 JSON 数据的标配——AI 中绝大多数配置文件(YAML/JSON)加载到 Python 后就是嵌套字典。TensorFlow/Keras 的模型配置就是典型的嵌套字典结构。PyTorch 的 state_dict 保存模型权重时也使用嵌套结构(层名→参数名→参数张量)。理解和熟练操作嵌套字典,是处理任何结构化数据的必备技能。
概念关系图谱
| 概念 | 核心含义 | 与AI的关系 | 关联概念 |
|---|---|---|---|
| dict | 键值对映射,O(1) 查找 | 词表映射、配置管理、缓存结果 | JSON、哈希表 |
| key-value | 键和值的配对存储 | label→idx、idx→label 双向映射 | 映射、关联数组 |
| get() | 安全访问,不存在返回默认值 | 未知词处理、配置缺省值 | setdefault()、in |
| items() | 遍历键值对迭代器 | 遍历词表、特征映射、训练统计 | keys()、values() |
| update() | 合并字典,键重复则覆盖 | 合并超参数、更新模型配置 | 解包合并、| 运算符 |
| 字典推导式 | 一行构建/过滤/变换字典 | 快速构建映射表、数据格式转换 | 列表推导式 |
| 嵌套字典 | 字典的值也是字典 | 模型架构配置、JSON数据解析 | 递归、树结构 |
| 哈希 | 将键映射为存储位置的算法 | 快速查找、去重、缓存 | 哈希表、不可变 |
重点答疑
Q1: 字典的键可以是什么类型?为什么列表不能做键?
字典的键必须是不可变且可哈希的类型。可用的有:字符串(str)、整数(int)、浮点数(float)、元组(tuple,前提是元组内元素都不可变)、布尔值(bool)、frozenset。不可用的有:列表(list)、字典(dict)、集合(set)——因为它们是可变的。原因在于字典底层使用哈希表——Python 对键调用 hash() 函数计算存储位置,而可变对象的哈希值在内容变化时会改变,导致字典查找就找不到原来存的数据了。列表没有实现 __hash__ 方法,所以直接报 TypeError。
Q2: d[key] 和 d.get(key) 有什么区别?
d[key] 直接访问:键存在返回对应值,键不存在抛出 KeyError 异常。d.get(key, default) 安全访问:键存在返回对应值,键不存在返回 default(默认为 None),不抛异常。实际开发中推荐使用 get()——特别是处理外部数据(API 响应、用户输入)时,你无法保证键一定存在。除非你确定键必须存在(不存在说明程序有 bug,应该尽早报错),这时用 [] 更好——"fail fast" 原则。
Q3: Python 3.7+ 的字典是有序的还是无序的?
从 Python 3.7 开始,字典正式保证保持插入顺序。这意味着遍历 d.keys()、d.values()、d.items() 时,返回的顺序就是键值对插入的顺序。注意:这不是"排序"——如果你按 ["c", "a", "b"] 的顺序插入,遍历时也是这个顺序,而不是按字母排序。在 Python 3.6 中这是 CPython 的实现细节,3.7 起成为语言规范。如果你需要排序遍历,仍然要用 sorted(d.items())。
Q4: 字典和 JSON 是什么关系?
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,语法和 Python 字典几乎一样——都用花括号和键值对。但有几个重要区别:①JSON 的键必须用双引号(Python 单双引号都行);②JSON 的值只能是字符串、数字、布尔、数组(列表)、对象(字典)、null,不支持 Python 的元组、集合、datetime 等;③JSON 是字符串格式,需要用 json.loads() 解析成字典、json.dumps() 序列化回字符串。AI 中几乎所有 API 交互都用 JSON,所以"字典 ⟷ JSON 互转"是最基本操作。
Q5: 如何合并两个字典?Python 3.9+ 有什么新写法?
有三种主流方式。①d1.update(d2):原地修改 d1,把 d2 合并进去(键重复时 d2 覆盖 d1);②{**d1, **d2}:解包合并,创建新字典(键重复时右边的覆盖左边);③Python 3.9+ 新增的合并运算符 d1 | d2(返回新字典)和 d1 |= d2(原地合并)。推荐 Python 3.9+ 用 | 运算符,3.5-3.8 用 {**d1, **d2}。
章节单词汇总
| 英文 | 音标 | 术语/释义 |
|---|---|---|
| dictionary | /ˈdɪkʃəneri/ | 字典;键值对集合 |
| key | /kiː/ | 键;用于查找值的索引词条 |
| value | /ˈvæljuː/ | 值;键对应的数据内容 |
| hash | /hæʃ/ | 哈希;将任意数据映射为固定长度的值 |
| mutable | /ˈmjuːtəbl/ | 可变的;可以修改的 |
| iterate | /ˈɪtəreɪt/ | 迭代;逐个遍历元素 |
| nested | /ˈnestɪd/ | 嵌套的;字典的值也是字典 |
| JSON | /ˈdʒeɪsən/ | JavaScript对象表示法;数据交换格式 |
面试练习
Q1 [单选] 以下创建字典的方式,哪个是错误的?
- A.
d = {"name": "Alice"} - B.
d = dict(name="Alice") - C.
d = dict([("name", "Alice")]) - D.
d = {"name", "Alice"}
解答:D 错误——{"name", "Alice"} 是集合(set)的语法,不是字典。字典需要冒号分隔键值对。A、B、C 都是合法的字典创建方式。
Q2 [单选] d = {"a": 1, "b": 2}; print(d.get("c", 0)) 输出什么?
- A. 报错 KeyError
- B. None
- C. 0
- D. "c"
解答:C 正确。get("c", 0)查找键 "c",不存在则返回默认值 0,不会报错。如果写成d["c"]则会报 KeyError。
Q3 [单选] 以下哪个可以作为字典的键?
- A.
[1, 2](列表) - B.
{"a": 1}(字典) - C.
(1, 2)(元组) - D.
{1, 2}(集合)
解答:C 正确。元组是不可变类型,可以作为字典的键。A(列表)、B(字典)、D(集合)都是可变的,不可哈希,不能作为字典的键。
Q4 [多选] 关于字典遍历,以下说法正确的是?
- A.
for k in d:默认遍历键 - B.
for v in d.values():遍历值 - C.
for k, v in d.items():同时遍历键和值 - D. 字典不能直接遍历
解答:A、B、C 都正确。D 错误——字典可以直接遍历(默认遍历键)。三种遍历方式各有适用场景。
Q5 [单选] d1 = {"a": 1}; d2 = {"b": 2}; d1.update(d2); print(d1) 输出什么?
- A.
{"a": 1, "b": 2} - B.
{"a": 1} - C.
{"b": 2} - D. 报错
解答:A 正确。update()把 d2 的键值对合并到 d1 中。同名键会覆盖。注意update()是原地修改 d1,返回 None。
Q6 [多选] 以下关于字典的说法正确的是?
- A. Python 3.7+ 字典保持插入顺序
- B.
len(d)返回字典中键值对的数量 - C. 字典的键必须都是字符串类型
- D.
"x" in d检查键 "x" 是否在字典中
解答:A、B、D 正确。C 错误——字典的键可以是任何不可变类型(整数、浮点数、元组、字符串等),不限于字符串。
Q7 [单选] d = {"x": 1, "y": 2}; d["z"] += 1 执行后会发生什么?
- A.
d["z"]变成 1 - B.
d["z"]变成 None - C. 抛出 KeyError
- D.
d["z"]变成 0
解答:C 正确。d["z"]键 "z" 不存在,访问时直接抛 KeyError,+= 1根本没有机会执行。正确做法是先用d.get("z", 0)获取值,或使用collections.defaultdict。
Q8 [多选] d = {"x": 10, "y": 20, "z": 10},以下操作正确的是?
- A.
d.pop("y")返回 20 - B.
d.pop("w", -1)返回 -1 - C.
d.clear()清空字典 - D.
d.popitem()总是删除并返回第一个键值对
解答:A、B、C 正确。D 错误——Python 3.7+ 中 popitem() 删除的是最后插入的键值对(LIFO),不是第一个。
Q9 [单选] 以下字典推导式的结果是什么?{x: x**2 for x in range(3)}
- A.
{0: 0, 1: 1, 2: 4} - B.
{1: 1, 2: 4, 3: 9} - C.
[0, 1, 4] - D.
{0: 0, 1: 1, 2: 4, 3: 9}
解答:A 正确。range(3)产生 0、1、2,字典推导式生成{0: 0², 1: 1², 2: 2²}={0:0, 1:1, 2:4}。注意 range 从 0 开始。
Q10 [多选] 合并两个字典 a = {"x": 1} 和 b = {"y": 2, "x": 100},想要 {"x": 100, "y": 2}(重复键用 b 的值),以下哪些方式正确?
- A.
{**a, **b} - B.
a | b(Python 3.9+) - C.
a | b(结果正确但需要 Python 3.9+) - D.
a.update(b)后再用 a
解答:A 和 D 都正确。{**a, **b}右边覆盖左边,结果为{"x": 100, "y": 2}。update(b)也是 b 覆盖 a。Python 3.9+ 中a | b返回新字典,b 覆盖 a。