news 2026/10/13 11:49:11

Python字典及字典基本操作方法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python字典及字典基本操作方法详解

前言


字典(dict)提供了一批内置方法,名字都短,但行为差别不小:get和setdefault都能「给个默认值」,可一个只读不写、一个会写回去;pop和popitem都删东西,但一个删你指定的键、一个删末尾;keys/values/items返回的是视图而不是列表。这些差别如果只靠猜,很容易写出「看起来对、跑起来错」的代码。


本文不铺陈概念,直接一个方法一个方法地过:给出它的签名(形参怎么传、/前后是位置还是关键字、有没有默认值),再说明它返回什么、是原地修改还是返回新对象。所有签名以 Python 官方文档为准,示例可在 Python 3.8 及以上运行;个别方法标注了更高的版本要求。


逐个方法讲完,最后一节用表格汇总,并列出常见坑点。


一、读值:get(key, default=None, /)


get返回键对应的值;键不存在时返回default,default省略则为None。它从不抛KeyError,也从不修改字典。


# 适用于 Python 3.8+
d = {"a": 1, "b": 2}
print(d.get("a")) # 1
print(d.get("z")) # None
print(d.get("z", 0)) # 0
print(d) # {'a': 1, 'b': 2},字典没变

注意签名里的/:d.get("z", 0)这样按位置传没问题,但d.get(key="z")会报TypeError,因为这两个参数都是仅位置参数。


二、缺键才写:setdefault(key, default=None, /)


setdefault是get的「带写入」版本:键在,返回值;键不在,先插入key: default,再返回default。


# 适用于 Python 3.8+
d = {"a": 1}
print(d.setdefault("a", 99)) # 1,已存在就不覆盖
print(d.setdefault("b", 2)) # 2,不存在则写入
print(d) # {'a': 1, 'b': 2}

s这个语义让它成为「分组建桶」的利器,后面在实战篇里会用到。它的默认值同样是None。


三、批量更新:update(...)


update有几种调用形式:update(mapping, /, **kwargs)、update(iterable, /, **kwargs)、update(**kwargs)。它原地把另一个映射或键值对序列合并进来,覆盖已有键,返回None。


# 适用于 Python 3.8+
d = {"a": 1}
d.update({"b": 2, "a": 100}) # 传映射
d.update([("c", 3)]) # 传键值对序列
d.update(d=4) # 传关键字参数
print(d) # {'a': 100, 'b': 2, 'c': 3, 'd': 4}

update返回None是常见误解点:它不返回新字典。


四、删除:pop(key, /)与popitem()


pop(key, /)删除指定键并返回其值;键不存在且没给默认值就抛KeyError;给了默认值d.pop(key, default)则返回默认值。


# 适用于 Python 3.8+
d = {"a": 1, "b": 2}
print(d.pop("a")) # 1
print(d.pop("z", None)) # None
print(d) # {'b': 2}

popitem()不接受参数,删除并返回最后一个键值对,从 Python 3.7 起保证是 LIFO(后进先出)。空字典上调用会抛KeyError。


# 适用于 Python 3.8+
d = {"a": 1, "b": 2, "c": 3}
print(d.popitem()) # ('c', 3),最后插入的先出
print(d.popitem()) # ('b', 2)

五、清空与拷贝:clear()和copy()


clear()删除全部项,返回None。copy()返回一个浅拷贝:新字典是新的对象,但里面嵌套的可变值仍与原字典共享。


# 适用于 Python 3.8+
d = {"a": 1, "b": {"n": 1}}
e = d.copy()
e["a"] = 99 # 顶层互不影响
e["b"]["n"] = 88 # ❗ 内层还是同一个对象
print(d) # {'a': 1, 'b': {'n': 88}}

d.clear()
print(d) # {}

六、三个视图:keys()、values()、items()


三者都返回视图对象:动态反映字典变化,支持len()和in。keys()的返回项是键,values()是值,items()是(key, value)元组。键视图和项视图还支持集合运算。


# 适用于 Python 3.8+
d = {"a": 1, "b": 2}
print(list(d.keys())) # ['a', 'b']
print(list(d.values())) # [1, 2]
print(list(d.items())) # [('a', 1), ('b', 2)]
print(d.keys() & {"b", "c"}) # {'b'},键视图可做交集

有一个反直觉的事实:d.values()之间比较永远为False,即使内容一样,因为值视图不保证唯一、不被当作集合。


# 适用于 Python 3.8+
d = {"a": 1}
print(d.values() == d.values()) # False

七、从序列造字典:fromkeys(iterable, value=None, /)


fromkeys是类方法,返回一个新字典,键来自iterable,所有键共用同一个value。


# 适用于 Python 3.8+
keys = ["a", "b", "c"]
d = dict.fromkeys(keys)
print(d) # {'a': None, 'b': None, 'c': None}

d2 = dict.fromkeys(keys, 0)
print(d2) # {'a': 0, 'b': 0, 'c': 0}

关键陷阱在下一节第一条:如果value是可变对象(比如空列表),所有键会共享同一个列表。


八、合并:|与|=(Python 3.9+)


d | other返回新字典,d |= other原地更新,两者都是other的值优先。这与集合的|(并集)语义不同,别混。


# 适用于 Python 3.9+
a = {"x": 1, "y": 2}
b = {"y": 20, "z": 30}
print(a | b) # {'x': 1, 'y': 20, 'z': 30},a 未被改动
a |= b
print(a) # {'x': 1, 'y': 20, 'z': 30},a 被改动

Python 3.9 之前,等价写法是{**a, **b}(新字典)和a.update(b)(原地)。


常见坑点


坑一:用可变对象做fromkeys的值。


# 适用于 Python 3.8+
# ❌ 三个键共享同一个列表
d = dict.fromkeys(["a", "b", "c"], [])
d["a"].append(1)
print(d) # {'a': [1], 'b': [1], 'c': [1]}
# ✅ 用字典推导式,每个键各建一个
d = {k: [] for k in ["a", "b", "c"]}
d["a"].append(1)
print(d) # {'a': [1], 'b': [], 'c': []}

坑二:把setdefault当纯读取用。


# 适用于 Python 3.8+
# ❌ 只想读,却顺手写进了一个键
d = {"a": 1}
d.setdefault("b") # 返回 None,同时 d 变成 {'a': 1, 'b': None}
# ✅ 只读用 get
d.get("b") # 仅返回 None,不写

坑三:以为pop("k", v)的第二个参数是「默认保留值」。


# 适用于 Python 3.8+
# ❌ 它不是「取不到就用这个值代替原值」,而是「取不到就返回它」
d = {"a": 1}
print(d.pop("a", 0)) # 1,能取到就返回真值
print(d.pop("a", 0)) # 0,已删掉,返回默认值
# ✅ 想「有就删、没有忽略」就显式传默认值
d.pop("z", None)

坑四:对空字典调用popitem()。


# 适用于 Python 3.8+
# ❌ 空字典上 popitem 抛 KeyError
d = {}
d.popitem() # KeyError: 'popitem(): dictionary is empty'
# ✅ 先判空,或用 pop 给默认值
if d:
d.popitem()
d.pop("missing", None)

坑五:以为values()能直接比大小。


# 适用于 Python 3.8+
# ❌ 值视图之间永远不等
d = {"a": 1}
print(d.values() == d.values()) # False
# ✅ 转成 list 再比
print(list(d.values()) == list(d.values())) # True

坑六:copy()之后修改嵌套结构。


# 适用于 Python 3.8+
# ❌ 浅拷贝只到第一层
d = {"cfg": {"verbose": False}}
e = d.copy()
e["cfg"]["verbose"] = True
print(d["cfg"]["verbose"]) # True,原字典也变了
# ✅ 要彻底隔离用 deepcopy
import copy
e = copy.deepcopy(d)

坑七:在 3.9 以前用|合并字典。


# 适用于 Python 3.9+
# ❌ 3.8 及更早版本没有字典的 | 运算符,这行会抛 TypeError
# d = {"a": 1} | {"b": 2}

# ✅ 3.9+ 可以直接用 |;需要在旧版本跑就改用 {**a, **b}
d = {**{"a": 1}, **{"b": 2}}
print(d) # {'a': 1, 'b': 2}

总结




方法返回是否改原字典要点



get(k, d=None)值或默认否从不抛KeyError

setdefault(k, d=None)值或默认缺键时写会插入

update(...)None是覆盖已有键

pop(k[, d])被删的值是缺键可给默认

popitem()(k, v)是3.7 起 LIFO

clear()None是清空

copy()新字典否浅拷贝

keys/values/items()视图否动态、可迭代

fromkeys(seq, v)新字典否可变值会共享

`\/\=`新字典 /None



记牢三组对比就不容易出错:get不写、setdefault会写;pop删指定键、popitem删末尾;|出新字典、|=改原字典。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 11:47:52

人工智能日报:五条工程信号与长上下文评测、端侧成本实操

做AI日报这段时间,我发现一件很有意思的事:越到2026年,行业里每天能拿出来说的“大新闻”反而越难写了。不是说AI没进展,而是大多数进展的形状太相似——模型更大、上下文更长、评测分数更高,但让一线工程师真正手痒的…

作者头像 李华
网站建设 2026/10/13 11:46:47

三合一效率神器:剪贴板历史+全局搜索+快速笔记实测

最近我在某个代码托管平台上的工具合集里翻到一个效率神器,用下来真的只想说一句话:太流批了,神仙工具,值得收藏。具体名字我就不念了,公开页面生成一长串英文字母,我叫它“小拾”。它的核心工作是把三件每…

作者头像 李华
网站建设 2026/10/13 11:46:10

递归下降分析实战:从文法改造到语法树构建与表达式求值

简介:这份编译原理实验资料面向计算机专业学生及编译器初学者,聚焦自上而下语法分析中的递归下降分析法,帮助读者掌握从文法改造到程序实现的完整流程。资源包内含1个doc文档,约80KB,以实验报告形式呈现,涵…

作者头像 李华
网站建设 2026/10/13 11:45:56

一文搞懂RAM/ROM/SRAM/DRAM/SDRAM/NOR/NAND选型

上周帮朋友排查一块板子,现象很奇怪:程序烧进去能跑,但只要一断电,之前配好的参数全变回出厂值。查了半天,发现是有人把配置数据放在了RAM里。这让我想起这些年带硬件团队、做方案评审时经常被问的一个问题&#xff1a…

作者头像 李华
网站建设 2026/10/13 11:45:05

SELinux强制访问控制(MAC)原理与实战配置指南

1. 这不是“开个开关”那么简单:SELinux到底在保护什么,为什么非它不可 你点开这篇教程,大概率是因为系统提示“SELinux is disabled”,或者某次安全扫描报告里赫然写着“SELinux未启用,存在权限提升风险”。但别急着去…

作者头像 李华