字典(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。