for k in d只遍历键(等价于d.keys()),for k, v in d.items()才遍历键值对;误用for k, v in d会报valueerror;d.items()返回视图对象,修改字典时需转list避免runtimeerror。

遍历字典时用 for k in d 和 for k, v in d.items() 有啥区别?
只写 for k in d 实际上遍历的是键(等价于 for k in d.keys()),不是键值对。想同时拿到键和值,必须显式调用 .items()。很多人误以为 for k, v in d 能解包,结果直接报 ValueError: too many values to unpack。
-
for k in d:最轻量,只读键,适合判断存在性或构造新键列表 -
for k, v in d.items():真正遍历键值对,Python 3.7+ 保证插入顺序 -
for v in d.values():只关心值,避免重复查键,内存更省
注意:d.items() 在 Python 3 返回视图对象(view),不是 list;若需多次迭代或修改字典,得先转成 list(d.items()),否则可能触发 RuntimeError: dictionary changed size during iteration。
用 dict.get() 还是 try/except KeyError 查键?
看场景。如果「键大概率存在」,用 dict.get(key, default) 更简洁安全;如果「键极少存在,且缺省逻辑复杂」,try/except 反而更清晰、性能略优(避免每次调用函数开销)。
-
d.get('x')返回None,d.get('x', 'N/A')返回默认值 -
try: v = d['x']触发KeyError时才进except,异常成本在 CPython 中其实不高 - 别用
if 'x' in d: v = d['x']—— 属于“先检查后访问”,有竞态风险(多线程下字典可能被删),也多一次哈希查找
一个典型坑:d.get('x', some_expensive_function()) 会总是执行 some_expensive_function(),哪怕键存在。此时应改用 try/except 或先判断。
立即学习“Python免费学习笔记(深入)”;
dict.setdefault() 和 collections.defaultdict 选哪个?
setdefault() 是单次操作,适合“取值,不存在则设初值并返回”;defaultdict 是长期策略,适合整个生命周期都预期大量缺失键的场景(比如分组统计)。
-
d.setdefault('k', []).append(x):安全追加,但每次调用都做一次哈希查找 + 条件赋值 -
dd = defaultdict(list); dd['k'].append(x):首次访问自动初始化,后续直接用,代码更干净 - 注意:
defaultdict一旦设了 default_factory,所有未定义键都会被自动创建,可能导致意外键膨胀(比如打错键名也不报错) - 想保留普通
dict行为又带默认逻辑?用dict.setdefault()更可控,或封装成辅助函数
别把 defaultdict(int) 当计数器用在高并发写入场景——它不是线程安全的,+= 操作仍可能丢更新。
为什么 json.dumps() 有时报 TypeError: Object of type dict is not JSON serializable?
这个错误几乎从不因为字典本身,而是字典里混入了非标准 JSON 类型:比如 datetime、set、自定义类实例、或 NaN / inf 浮点数。
- 常见诱因:
d = {'ts': datetime.now(), 'tags': {'a', 'b'}}——set不可序列化,datetime也不行 - 解法一:预处理,用
json.dumps(d, default=str)把所有无法序列化的对象转成字符串(简单粗暴,适合调试) - 解法二:写定制
default函数,专门处理datetime→ ISO 字符串,set→list,bytes→ base64 等 - 解法三:用
dataclasses.asdict()或pydantic.BaseModel.dict()提前规整数据结构
容易忽略的一点:字典的键必须是字符串,如果用了 int 或 tuple 作键(合法 Python dict),json.dumps() 会静默忽略该键值对,不报错也不警告。










