python中字典怎么单独加键,几种写法和踩坑记录
- 2026年11月9日
- 34 次
上周五晚上快十一点,我在改一个抓取脚本的配置,需要往已有的字典里单独塞一个键,结果手一滑写岔了,取值全是 None。当时第一反应是字典坏了,赶紧翻文档,索性把 python中字典怎么单独加键 的几种写法从头试了一遍,顺手记成这篇,也给自己留个底。
用方括号直接赋值加键,九成场景就它
我最早学的写法就是 d["k"] = v。它做的事很直白:键不存在就新建,存在就覆盖。给配置字典补一个字段,我基本都用它,一行就完事。

真正要小心的是覆盖。你如果只想「有就保留、没有才补」,方括号会把你原来的值冲掉。我在日志配置上白跑过一次,level 被脚本改成 DEBUG,排查了半天才想起来是这行。
cfg = {"host": "127.0.0.1", "port": 8080}
cfg["timeout"] = 5 # 新键,直接加上
cfg["port"] = 9000 # 旧键,值被覆盖
print(cfg["port"]) # 9000
输出就一行 9000,这就是覆盖的证据。所以在写 python中字典怎么单独加键 的代码之前,我会先问自己一句:这个键可能已经存在吗。

会存在又不想动,那就别用方括号。这是我现在的习惯,比事后回滚省事得多。其实很多人踩坑都不是不会写,而是没想清楚要不要保留旧值。
还有个细节值得记一下:字典是可变对象。你把字典传进函数,在函数里用方括号加键,外面那份也看得见。我第一次碰这个,以为函数里改的是副本,结果主流程里的配置被悄悄改了。
不是 bug,是对象引用。你把 python中字典怎么单独加键 的代码写进工具函数时,要么明确它就是修改原字典,要么先 copy 一份再动手,别让调用方猜。
setdefault 和 update 的差别,第一次用容易搞混
setdefault 的逻辑是「没有才写」,这也是 python中字典怎么单独加键 里最常被误会的一个方法。键已存在时它不改值,还把旧值返回给你;键不存在才插入默认值。我第一次用它,以为它会强制写入,结果调试了半小时。
update 是批量合并。传进去的字典里每个键都往目标字典里塞,重复的键照样覆盖。你要加一批键,用它比循环赋值干净;只加一个键,用它反而绕。
d = {"a": 1}
d.setdefault("a", 99) # 已存在,值还是 1
d.setdefault("b", 2) # 不存在,插入 2
d.update({"b": 20, "c": 3}) # b 被改成 20
print(d) # {'a': 1, 'b': 20, 'c': 3}
输出大概长这样,重点看 b:setdefault 没碰它,update 把它改了。搞清楚 setdefault 和 update 的差别,你写 python中字典怎么单独加键 的时候就不太会选错。
老实说这两个方法的返回值也不一样。setdefault 返回该键对应的值,update 返回 None。把它们塞进链式调用里混用,报错信息会很难看。

我现在的判断很粗暴:单个键、要保留旧值,用 setdefault;单个键、要覆盖,直接赋值;一批键,才轮到 update。这三句话能覆盖我在业务里遇到的大部分情况。
嵌套字典加键,父级路径得先存在
多层字典最容易翻车,这也是 python中字典怎么单独加键 里最费神的一段。d["a"]["b"] = 1 的前提是 d["a"] 已经是个字典:d 里没有 a,抛的是 KeyError;a 在但不是字典(比如是字符串),抛的是 TypeError。我第一次写采集脚本,就在这行崩过。
稳妥的写法是逐层 setdefault,先保证外层键在,再往里写:
d = {}
d.setdefault("a", {}).setdefault("b", 1)
print(d) # {'a': {'b': 1}}
层级深的时候这么写有点啰嗦,但比 try 包一层清楚,出问题也知道断在哪一级。
还有一种情况是键名来自变量。这时候别手拼字符串,直接用变量当下标就行,Python 不区分你给的是字面量还是变量。
层次固定又比较深的时候,我索性把路径写成列表,循环一遍逐个 setdefault。看着绕,其实是把「哪一级缺」交给循环处理,比自己写三层判断短,也不容易漏层。
批量导入时我常干的活:把一行数据整理成小字典,再 update 进主字典。键冲突的地方要先定好谁优先,不然跑完发现数据被默默覆盖,很难查。
这也是我在 python中字典怎么单独加键 上花时间最多的地方。单层写法一分钟能学会,嵌套结构里的层级判断,得靠具体业务喂出来。
键总在判断存在性,就换 defaultdict
如果你每次加键前都要判断存在性,键的类型还固定,defaultdict 更顺手。访问不存在的键时它会自动建默认值,那层判断就省了。写统计就是这么开头:from collections import defaultdict,stat = defaultdict(list),然后 stat["k"].append(1) 直接往里塞。
代价是它会「凭空造键」,连取值都会插入。这点和 get 不一样。你只想读不想写的时候,老老实实用 get,别拿 defaultdict 顶。
我踩过一次:写统计脚本时用 defaultdict(list) 累加,中途想判断某个键有没有被访问过,结果判断本身就把键造出来了。后来改成先 get 一次,逻辑才说得通。
我现在加键的顺序
拿到一个字典,第一步看键会不会重复:可能重复又要保留旧值的,走 setdefault;确定要覆盖的,方括号一把梭;一次加好几个,update。
第二步看层级:嵌套结构先补父级再写子级。这一步很容易漏,我吃过亏,报错还只指向最里面那一层,往上翻好几层才看到根。
键名来自循环或接口返回时,我会先把候选键打印一遍再写。折腾这几分钟,比跑完发现字段全是旧值划算,尤其是批量任务。
python中字典怎么单独加键 这件事说到底就三条路:赋值、setdefault、update,剩下的都是组合。判断依据只有一个:你到底要不要保留旧值。
我把这套顺序写在便签上贴过一阵,后来熟了才撕掉。你要是刚接手别人的脚本,先按这个顺序读一遍,能很快看出它想覆盖还是想补缺。
我的经验是先把「要不要覆盖」定死,再挑写法,别一边写一边改主意。先定覆盖、再挑方法、最后才想层级,这个顺序我改过两回才理顺。
若非作者标注皆为李涛自留地原创文章,转载或复制请以超链接形式并注明出处。
- html文本框的基本语法 Html文本框如何使用? 2022-06-22
- PHP中如何创建临时文件 PHP中创建临时文件的方法 2022-11-10
- PHP array_combine() 函数详解:用两个数组构造键值对 2026-07-02
- wordpress中启用wp githuber md前端代码无法高亮? 2021-03-01
- 正则表达式中文汉字如何匹配?正则表达式匹配中文汉字规则 2022-11-26
- 搞不清php session默认过期时间,回收机制踩坑记 2026-11-09
