当前位置: 代码网 > it编程>前端脚本>Python > Python中字典的12种遍历方式和20个常用操作全攻略

Python中字典的12种遍历方式和20个常用操作全攻略

2026年08月27日 Python 我要评论
摘要字典是 python 中使用频率最高的数据结构之一,但你真的用对了吗?本文从零梳理字典的核心概念,给出 12 种遍历方式(从基础 for 循环到排序遍历、嵌套展开全覆盖),整理 20+ 个常用操作

摘要

字典是 python 中使用频率最高的数据结构之一,但你真的用对了吗?本文从零梳理字典的核心概念,给出 12 种遍历方式(从基础 for 循环到排序遍历、嵌套展开全覆盖),整理 20+ 个常用操作(增删改查、合并、推导式,每个都带可运行代码和输出注释),并深入讲解 json 序列化与反序列化的实战技巧(中文不乱码、datetime 等不可序列化对象的处理方案)。文末附完整速查表,适合收藏随时查阅。

不管你是刚学 python 的新手,还是想系统补全字典知识的老手,这篇 5000+ 字的硬核攻略都能让你一次彻底搞懂 python 字典!

一、字典基础入门

1.1 什么是字典

字典(dict)是 python 中存储 键值对(key-value pair) 的数据结构。你可以把它理解为一本真实的字典: 是你要查的词(word), 是该词的解释(definition)。通过"键"来快速定位"值",这就是字典的核心用途。

# 一本最简词典
word_book = {
    "apple": "苹果",
    "banana": "香蕉",
    "cat": "猫"
}
print(word_book["apple"])  # 苹果

字典在 python 3.7+ 中 默认保持插入顺序(3.6 是 cpython 实现细节,3.7 起成为语言规范),这意味着你按什么顺序放进去,遍历时就按什么顺序取出来。

1.2 创建字典的多种方式

除了最常用的 {} 字面量,python 还提供了多种创建字典的方法,不同场景有不同选择:

# 方式1: 花括号字面量(最常用)
d1 = {"name": "alice", "age": 25}

# 方式2: dict() 构造函数 + 关键字参数
d2 = dict(name="bob", age=30)

# 方式3: dict() + 可迭代对象(每个元素是长度为2的序列)
d3 = dict([("name", "charlie"), ("age", 28)])

# 方式4: 字典推导式
d4 = {x: x ** 2 for x in range(1, 5)}
print(d4)  # {1: 1, 2: 4, 3: 9, 4: 16}

# 方式5: dict.fromkeys() 批量创建
d5 = dict.fromkeys(["a", "b", "c"], 0)
print(d5)  # {'a': 0, 'b': 0, 'c': 0}

# 方式6: zip() 组合两个列表
keys = ["name", "age", "city"]
values = ["david", 22, "beijing"]
d6 = dict(zip(keys, values))
print(d6)  # {'name': 'david', 'age': 22, 'city': 'beijing'}

1.3 字典的核心特性

特性说明举例
键唯一重复键后面的值覆盖前面的{"a": 1, "a": 2} 结果为 {"a": 2}
键必须可哈希键只能是不可变类型(str、int、tuple 等){[1, 2]: "a"} 报 typeerror
值任意类型值可以是任何 python 对象{"fn": lambda x: x+1} 合法
可变可以原地增删改d["new_key"] = "val"
动态大小随增删自动调整无需预定义容量
有序 (3.7+)保持键值对的插入顺序遍历顺序 = 添加顺序

二、字典的遍历 — 12 种方式全覆盖

遍历字典看似简单,但在不同场景下选择正确的遍历方式,代码可读性和效率会有明显差异。以下按使用频率从高到低整理。

2.1 for key in dict — 直接遍历键

最简洁的写法,for k in d 等价于 for k in d.keys(),但前者更高效(省去方法调用开销)。

score = {"math": 90, "english": 85, "chinese": 92}

for k in score:
    print(k, "->", score[k])
# math -> 90
# english -> 85
# chinese -> 92

2.2 .keys() — 显式遍历键

当你需要明确表达"遍历键"的意图,或者要对键做集合运算时使用。

for k in score.keys():
    print(k)
# math
# english
# chinese

# .keys() 返回的是动态视图,可以参与集合运算
print(score.keys() & {"math", "art"})  # {'math'}

2.3 .values() — 只遍历值

不关心键是什么,只对值做统计或处理时使用。

for v in score.values():
    print(v)
# 90
# 85
# 92

# 常见用法:求和、求平均
total = sum(score.values())
avg = total / len(score)
print(total, avg)  # 267 89.0

2.4 .items() — 同时遍历键和值

最常用的遍历方式,一次拿到键和值,避免在循环体内重复取值。

for subject, mark in score.items():
    print(f"{subject}: {mark}分")
# math: 90分
# english: 85分
# chinese: 92分

2.5 enumerate() — 带索引遍历

给遍历加上序号,适用于需要显示排名的场景。

for idx, (k, v) in enumerate(score.items(), start=1):
    print(f"第{idx}名: {k} {v}分")
# 第1名: math 90分
# 第2名: english 85分
# 第3名: chinese 92分

2.6 sorted() — 按键排序遍历

确保输出顺序完全可控(虽然 3.7+ 字典保持插入顺序,但有时需要按字母或数值排序)。

data = {"banana": 3, "apple": 5, "cherry": 2}

# 按键的字母序
for k in sorted(data):
    print(k, data[k])
# apple 5
# banana 3
# cherry 2

2.7 sorted() — 按值排序遍历

按值大小排序输出,统计排行场景必备。

data = {"banana": 3, "apple": 5, "cherry": 2}

# 按值升序
for k, v in sorted(data.items(), key=lambda x: x[1]):
    print(k, v)
# cherry 2
# banana 3
# apple 5

# 按值降序
for k, v in sorted(data.items(), key=lambda x: x[1], reverse=true):
    print(k, v)
# apple 5
# banana 3
# cherry 2

2.8 reversed() — 逆序遍历

配合 reversed() 从后往前遍历字典项。

d = {"a": 1, "b": 2, "c": 3}

for k in reversed(d):
    print(k, d[k])
# c 3
# b 2
# a 1

# 对 items 逆序
for k, v in reversed(d.items()):
    print(k, v)
# c 3
# b 2
# a 1

2.9 字典推导式 — 遍历并转换

边遍历边生成新字典,一行代码完成"过滤 + 转换"。

prices = {"apple": 5.5, "banana": 3.2, "orange": 4.8, "grape": 12.0}

# 遍历中过滤:只保留价格 >= 5 的水果
expensive = {k: v for k, v in prices.items() if v >= 5}
print(expensive)  # {'apple': 5.5, 'grape': 12.0}

# 遍历中转换:所有商品打八折
discounted = {k: round(v * 0.8, 1) for k, v in prices.items()}
print(discounted)  # {'apple': 4.4, 'banana': 2.6, 'orange': 3.8, 'grape': 9.6}

2.10 条件过滤遍历 — 遍历时筛选

不生成新字典,只对符合条件的项做处理。

inventory = {"apple": 10, "banana": 0, "orange": 5, "grape": 0}

# 找出库存为0的商品
for k, v in inventory.items():
    if v == 0:
        print(f"缺货: {k}")
# 缺货: banana
# 缺货: grape

2.11 嵌套字典遍历 — 多层展开

处理 json 数据或配置字典时经常遇到嵌套结构。

students = {
    "alice": {"age": 20, "score": 88},
    "bob":   {"age": 21, "score": 92},
    "charlie": {"age": 19, "score": 85}
}

for name, info in students.items():
    print(f"{name}: 年龄 {info['age']}, 成绩 {info['score']}")
# alice: 年龄 20, 成绩 88
# bob: 年龄 21, 成绩 92
# charlie: 年龄 19, 成绩 85

2.12 while + 迭代器遍历

不常用,但了解它有助于理解迭代器协议。实际开发中 for 循环是首选。

d = {"x": 10, "y": 20, "z": 30}
it = iter(d.items())

while true:
    try:
        k, v = next(it)
        print(k, v)
    except stopiteration:
        break
# x 10
# y 20
# z 30

遍历方式速查表

遍历方式语法适用场景
直接遍历键for k in d:只需键,最简洁
显式遍历键for k in d.keys():需要对键做集合运算
遍历值for v in d.values():只关心值,如求和统计
遍历键值对for k, v in d.items():同时需要键和值(最常用)
带索引for i, (k,v) in enumerate(d.items())需要显示序号
按键排序for k in sorted(d):保证字母/数值顺序
按值排序for k,v in sorted(d.items(), key=...)排行、取 top n
逆序for k in reversed(d):倒序输出
推导式{k: f(v) for k,v in d.items() if cond}过滤+转换,生成新字典
条件过滤if cond: inside for只处理符合条件的项
嵌套展开多层 for + 嵌套索引处理嵌套字典/json
迭代器while + next() + stopiteration理解迭代协议(不推荐日常用)

三、字典的常见操作 — 20+ 个方法与技巧

3.1 查 — 安全取值

取值是字典最高频的操作,但直接用 d[key] 在 key 不存在时会报 keyerror,因此 get() 往往是更好的选择。

user = {"name": "alice", "age": 25}

# 方式1: 直接索引(key 不存在报错)
print(user["name"])  # alice

# 方式2: get() — 安全取值,不存在返回 none
print(user.get("email"))  # none

# 方式3: get() + 默认值 — 最佳实践
print(user.get("email", "unknown@example.com"))  # unknown@example.com

# 方式4: setdefault() — 取不到就设置并返回
print(user.setdefault("role", "guest"))  # guest
print(user)  # {'name': 'alice', 'age': 25, 'role': 'guest'}
取值方法key 存在key 不存在典型用途
d[key]返回值抛 keyerror确定 key 一定存在时
d.get(key)返回值返回 none不确定 key 是否存在
d.get(key, default)返回值返回 default需要默认值时
d.setdefault(key, default)返回值设置并返回 default初始化缺失的 key

3.2 增 / 改 — 添加和更新

d = {"a": 1, "b": 2}

# 单个新增/修改
d["c"] = 3
print(d)  # {'a': 1, 'b': 2, 'c': 3}

# 批量更新 update()
d.update({"b": 99, "d": 4, "e": 5})
print(d)  # {'a': 1, 'b': 99, 'c': 3, 'd': 4, 'e': 5}

# python 3.9+ 并集运算符 | (返回新字典,不修改原字典)
d2 = {"f": 6, "g": 7}
merged = d | d2
print(merged)  # {'a': 1, 'b': 99, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7}
print(d)       # {'a': 1, 'b': 99, 'c': 3, 'd': 4, 'e': 5}  -- 原字典不变

# 原地更新 |=(python 3.9+)
d |= d2
print(d)       # {'a': 1, 'b': 99, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7}

# ** 解包合并(兼容老版本,返回新字典)
d3 = {"x": 10, "y": 20}
combined = {**d, **d3}
print(combined)  # {'a': 1, 'b': 99, ..., 'x': 10, 'y': 20}

3.3 删 — 安全删除

d = {"a": 1, "b": 2, "c": 3, "d": 4}

# pop(key) — 删除并返回值,key 不存在报错
val = d.pop("c")
print(val, d)  # 3 {'a': 1, 'b': 2, 'd': 4}

# pop(key, default) — 安全删除,不存在返回默认值
val = d.pop("z", "not found")
print(val)  # not found

# popitem() — 删除并返回最后一个键值对(lifo)
last = d.popitem()
print(last, d)  # ('d', 4) {'a': 1, 'b': 2}

# del — 直接删除(key 不存在报 keyerror)
del d["b"]
print(d)  # {'a': 1}

# clear() — 清空所有元素
d.clear()
print(d)  # {}

3.4 判断 — 存在性与长度

d = {"name": "alice", "age": 25}

# in 运算符 — 判断键是否存在(o(1) 时间复杂度)
print("name" in d)    # true
print("email" in d)   # false
print("email" not in d)  # true

# len() — 键值对数量
print(len(d))  # 2

# 判空
if not d:
    print("字典为空")
else:
    print(f"字典有 {len(d)} 项")
# 字典有 2 项

3.5 视图对象 — keys / values / items

这三个方法返回的都是 动态视图(view object),会随原字典变化而变化。

d = {"a": 1, "b": 2}
keys_view = d.keys()
vals_view = d.values()
items_view = d.items()

print(keys_view)   # dict_keys(['a', 'b'])
print(vals_view)   # dict_values([1, 2])
print(items_view)  # dict_items([('a', 1), ('b', 2)])

# 动态性:修改原字典后,视图自动反映变化
d["c"] = 3
print(keys_view)   # dict_keys(['a', 'b', 'c'])
print(vals_view)   # dict_values([1, 2, 3])

3.6 复制 — 浅拷贝与深拷贝

import copy

original = {"a": [1, 2, 3], "b": {"nested": true}}

# 浅拷贝:顶层独立,嵌套对象共享引用
shallow = original.copy()  # 等价于 dict(original) 或 {**original}
shallow["a"].append(4)
print(original["a"])  # [1, 2, 3, 4] — 原字典也被影响!

# 深拷贝:完全独立,递归复制所有嵌套对象
deep = copy.deepcopy(original)
deep["a"].append(5)
print(original["a"])  # [1, 2, 3, 4] — 原字典不受影响

3.7 fromkeys() — 批量初始化

# 用同一个默认值初始化所有键
keys = ["name", "age", "city"]
d = dict.fromkeys(keys, "n/a")
print(d)  # {'name': 'n/a', 'age': 'n/a', 'city': 'n/a'}

# 陷阱:默认值是可变对象时,所有键共享同一个对象!
d_bad = dict.fromkeys(["a", "b", "c"], [])
d_bad["a"].append(1)
print(d_bad)  # {'a': [1], 'b': [1], 'c': [1]} — 全部被改了!

# 正确做法:用字典推导式给每个键创建独立对象
d_good = {k: [] for k in ["a", "b", "c"]}
d_good["a"].append(1)
print(d_good)  # {'a': [1], 'b': [], 'c': []}

3.8 字典推导式 — 一行搞定过滤和转换

# 过滤:只保留成绩 >= 80 的高分选手
scores = {"alice": 90, "bob": 55, "charlie": 85, "david": 72}
passed = {k: v for k, v in scores.items() if v >= 80}
print(passed)  # {'alice': 90, 'charlie': 85}

# 转换:成绩转为等级
grades = {k: "优" if v >= 90 else "良" if v >= 70 else "中" if v >= 60 else "差"
          for k, v in scores.items()}
print(grades)  # {'alice': '优', 'bob': '差', 'charlie': '良', 'david': '中'}

# 键值互换
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(swapped)  # {1: 'a', 2: 'b', 3: 'c'}

四、json 序列化与反序列化

字典和 json 是天生的搭档——python 的 dict 与 json 的 object 高度对应。但序列化过程中有不少坑,这一章帮你全部避开。

4.1 核心概念

操作方向函数输入输出
序列化python → json 字符串json.dumps()dict/list/str/…str
反序列化json 字符串 → pythonjson.loads()strdict/list/…
写文件python → json 文件json.dump()dict + file写入文件
读文件json 文件 → pythonjson.load()filedict/list/…

4.2 dumps() / loads() — 内存中的序列化

import json

# 序列化:dict → json 字符串
user = {"name": "alice", "age": 25, "active": true, "tags": ["python", "web"]}
json_str = json.dumps(user)
print(json_str)
# {"name": "alice", "age": 25, "active": true, "tags": ["python", "web"]}
print(type(json_str))  # <class 'str'>

# 反序列化:json 字符串 → dict
parsed = json.loads(json_str)
print(parsed)           # {'name': 'alice', 'age': 25, 'active': true, 'tags': ['python', 'web']}
print(type(parsed))     # <class 'dict'>
print(parsed["name"])   # alice

4.3 中文不乱码 — ensure_ascii=false

默认情况下 json.dumps() 会把非 ascii 字符转义为 \uxxxx 格式。中文场景必须加上 ensure_ascii=false

data = {"title": "python 字典入门教程", "author": "张三"}

# 默认行为:中文被转义,完全不可读
print(json.dumps(data))
# {"title": "python 字典入门教程", "author": "张三"}

# 加上 ensure_ascii=false:中文原样保留
print(json.dumps(data, ensure_ascii=false))
# {"title": "python 字典入门教程", "author": "张三"}

4.4 排版美化 — indent 与 sort_keys

调试和日志场景下,紧凑的 json 难以阅读,使用 indentsort_keys 可以大幅提升可读性。

config = {
    "server": {"host": "0.0.0.0", "port": 8080},
    "database": {"engine": "postgresql", "pool_size": 10},
    "debug": false
}

pretty = json.dumps(config, indent=2, ensure_ascii=false, sort_keys=true)
print(pretty)
# {
#   "database": {
#     "engine": "postgresql",
#     "pool_size": 10
#   },
#   "debug": false,
#   "server": {
#     "host": "0.0.0.0",
#     "port": 8080
#   }
# }

4.5 dump() / load() — 读写 json 文件

# 写入 json 文件
config = {"version": "1.0", "settings": {"theme": "dark", "lang": "zh"}}

with open("config.json", "w", encoding="utf-8") as f:
    json.dump(config, f, ensure_ascii=false, indent=2)
# 文件内容:
# {
#   "version": "1.0",
#   "settings": {
#     "theme": "dark",
#     "lang": "zh"
#   }
# }

# 读取 json 文件
with open("config.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)
print(loaded["settings"]["theme"])  # dark

4.6 处理不可序列化的对象 — default 参数

datetimedecimal、自定义类等对象无法直接序列化,json.dumps() 会抛 typeerror。解决方案是自定义 default 函数。

from datetime import datetime, date
from decimal import decimal

data = {
    "user": "alice",
    "created_at": datetime.now(),
    "birthday": date(2000, 1, 15),
    "balance": decimal("99.99")
}

# 方式1:自定义 default 函数
def json_default(obj):
    if isinstance(obj, datetime):
        return obj.strftime("%y-%m-%d %h:%m:%s")
    if isinstance(obj, date):
        return obj.strftime("%y-%m-%d")
    if isinstance(obj, decimal):
        return float(obj)
    raise typeerror(f"object of type {type(obj).__name__} is not json serializable")

result = json.dumps(data, default=json_default, ensure_ascii=false, indent=2)
print(result)
# {
#   "user": "alice",
#   "created_at": "2026-07-20 10:30:00",
#   "birthday": "2000-01-15",
#   "balance": 99.99
# }

# 方式2:继承 jsonencoder(适合复用场景)
class customencoder(json.jsonencoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime("%y-%m-%d %h:%m:%s")
        if isinstance(obj, date):
            return obj.strftime("%y-%m-%d")
        if isinstance(obj, decimal):
            return float(obj)
        return super().default(obj)

result2 = json.dumps(data, cls=customencoder, ensure_ascii=false)

4.7 自定义反序列化 — object_hook

有时需要把 json 还原为特定的 python 对象,用 object_hook 可以拦截每一个被解析的 dict。

json_str = '''
{
    "user": "bob",
    "created_at": "2026-07-20 14:30:00",
    "balance": 128.50
}
'''

from datetime import datetime

def revive_dates(dct):
    """如果发现 created_at 字段,自动转回 datetime 对象"""
    result = {}
    for k, v in dct.items():
        if k.endswith("_at") and isinstance(v, str):
            try:
                result[k] = datetime.strptime(v, "%y-%m-%d %h:%m:%s")
            except valueerror:
                result[k] = v
        else:
            result[k] = v
    return result

parsed = json.loads(json_str, object_hook=revive_dates)
print(parsed)
# {'user': 'bob', 'created_at': datetime.datetime(2026, 7, 20, 14, 30), 'balance': 128.5}
print(type(parsed["created_at"]))  # <class 'datetime.datetime'>

4.8 python dict 与 json 类型对照

python 类型json 类型说明
dictobject键必须是字符串
list, tuplearraytuple 序列化后变 array,反序列化回 list
strstring
int, floatnumberjson 不区分整数和浮点数
true, falsetrue, false注意大小写
nonenull
datetime, decimal不支持需要自定义 default 函数

4.9 常见序列化陷阱与解决方案

陷阱现象解决方案
中文乱码中文ensure_ascii=false
datetime 报错typeerror: object is not json serializabledefault 参数转字符串
tuple 变 list反序列化后 tuple 丢失object_hook 手动恢复
大文件内存溢出加载大 json 文件卡顿ijson 等流式解析库
浮点数精度丢失1.1 + 2.2 不是精确的 3.3decimal + 自定义序列化

五、总结速查表

5.1 字典方法速查

方法说明返回值
d[key]访问元素值(不存在报错)
d.get(key, default)安全访问值或 default
d.keys()获取所有键dict_keys 视图
d.values()获取所有值dict_values 视图
d.items()获取所有键值对dict_items 视图
d.update(other)批量更新none(原地修改)
d[key] = val添加/修改
d.pop(key, default)删除并返回值值或 default
d.popitem()删除最后一项(key, value) 元组
del d[key]删除元素—(不存在报错)
d.clear()清空所有元素none
d.copy()浅拷贝新 dict
d.setdefault(key, default)取值,不存在则设置
dict.fromkeys(keys, val)批量创建(类方法)新 dict
key in d键是否存在bool
len(d)元素数量int
d1 | d2 (3.9+)合并(返回新字典)新 dict
d1 |= d2 (3.9+)合并(原地更新)
{**d1, **d2}解包合并新 dict
{k: v for ...}字典推导式新 dict

5.2 json 模块速查

函数方向适用场景
json.dumps(obj)python → str内存中序列化
json.loads(s)str → python内存中反序列化
json.dump(obj, f)python → 文件写入 json 文件
json.load(f)文件 → python读取 json 文件
dumps(..., ensure_ascii=false)保留中文
dumps(..., indent=2)美化输出
dumps(..., default=fn)自定义序列化
loads(..., object_hook=fn)自定义反序列化

本文从字典基础、12 种遍历方式、20+ 个常用操作,到 json 序列化与反序列化的实战技巧,已经全部覆盖。如果觉得有用,欢迎收藏、点赞,有任何问题或者你有更好用的字典技巧,也欢迎在评论区分享交流!

(本文使用 python 3.10 环境,所有代码均可直接运行。)

以上就是python中字典的12种遍历方式和20个常用操作全攻略的详细内容,更多关于python字典遍历与操作的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com