page contents

字典的 8 个进阶技巧:把 Python 最常用的结构用到精通!

字典是 Python 使用频率第一的数据结构——高频意味着「基础用法」人人都会,而真正拉开差距的是进阶惯用法:安全取值、合并、嵌套、视图、选型。

attachments-2026-10-svwXK55I6ae2a4a8166bb.png

字典是 Python 使用频率第一的数据结构——高频意味着「基础用法」人人都会,而真正拉开差距的是进阶惯用法:安全取值、合并、嵌套、视图、选型。

技巧 1:setdefault 与 defaultdict 的分工

config = {"timeout": 30}
config.setdefault("timeout", 60)     # 30(已存在,不动)
config.setdefault("retries", 3)      # 3(新建)

from collections import defaultdict
groups = defaultdict(list)
for item in data:
    groups[item["city"]].append(item)   # 访问即创建,无试探代码

分工一句话:偶尔兜底用 setdefault;「频繁分组/计数」直接 defaultdict——后者连「键是否存在」这个念头都不需要有。

技巧 2:字典合并的三代进化(| 运算符)

merged = defaults | overrides     # 后者覆盖前者
defaults |= overrides             # 原地合并

a = {"db": {"host": "a", "port": 1}}
b = {"db": {"host": "b"}}
a | b        # {'db': {'host': 'b'}} —— port 丢了!

| 只做浅合并——配置合并场景(默认配置 + 用户配置)里,嵌套字典被整体覆盖而不是逐键合并,这是 | 最容易埋雷的地方。

技巧 3:字典视图——keys/values/items 是「活的」

d = {"a": 1, "b": 2}
ks = d.keys()
d["c"] = 3
print(ks)          # dict_keys(['a', 'b', 'c']) —— 视图跟着变!

common = d1.keys() & d2.keys()       # 两字典共有的键
only_a = d1.keys() - d2.keys()       # 只在 d1 的键
d1.items() == d2.items()             # 键值对整体比较

视图不是快照是「直播」——调试时它自动更新很方便;但若要「留档」,必须 list() 物化。集合运算则是被严重低估的能力:对账类需求(找出两边共有的键)一行完成。

技巧 4:嵌套字典的安全访问

data = {"user": {"profile": {"city": "北京"}}}

data["user"]["profile"]["city"]

city = data.get("user", {}).get("profile", {}).get("city")

try:
    city = data["user"]["profile"]["city"]
except KeyError:
    city = "未知"

class Profile(BaseModel):
    profile: ProfileInfo

选型:偶尔一层不确定 → 链式 get;允许缺失但要求记录 → try;入口可控 → 模型校验。永远不要三层裸链——生产事故的常客。

技巧 5:字典推导 + 条件——批量构造与过滤

prices = {"apple": 5.0, "banana": 3.2, "cherry": 12.0}
expensive = {k: v for k, v in prices.items() if v > 4}
with_tax = {k: round(v * 1.1, 2) for k, v in prices.items()}
inverted = {v: k for k, v in prices.items()}
lookup = dict(zip(["A", "B", "C"], [1, 2, 3]))

技巧 6:字典的有序性——3.7+ 的语言保证

d = {}
d["c"] = 3
d["a"] = 1
list(d)             # ['c', 'a'] —— 按插入顺序

技巧 7:遍历时的修改纪律

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

for k in d:
    if d[k] < 2:
        del d[k]

for k in list(d):
    if d[k] < 2:
        del d[k]
d = {k: v for k, v in d.items() if v >= 2}
for k in d:
    d[k] *= 10

纪律的边界要记准:改「值」安全,增删「键」危险——很多 bug 出在「以为改值也不行(过度小心)」或「以为删键也行(侥幸)」两个方向。

技巧 8:选型决策——什么时候不用普通 dict

计数场景            → Counter(自动排序、most_common、算术运算)
分组场景            → defaultdict(list/set)
需要「访问顺序淘汰」  → OrderedDict(move_to_end / popitem(last=False))
键是「固定字段名」    → dataclass / NamedTuple(属性访问、IDE 补全、防拼错)
大规模只读查询       → dict 本身就是最优(O(1) 哈希)
需要「键也有序+冻结」 → frozendict(3.15 内置,Python 3.15 篇)

一个反直觉提醒:字段固定的结构化数据,用 dict 不如用 dataclass——order["usre_id"](拼错)不报错返回 KeyError 才发现,而 order.user_id 拼错在 IDE 里当场标红。dict 灵活,dataclass 安全——内外有别(Pydantic 篇的分层原则)。

速查表

d.setdefault(k, v) / defaultdict   兜底初始化 / 分组计数
d1 | d2                            合并(浅!嵌套会被整覆盖)
d1.keys() & d2.keys()              视图集合运算(对账神器)
链式 .get() / try / 模型校验        嵌套安全三选一,拒绝裸链
{k: v for k, v in d.items() if ...}   批量构造过滤
插入有序(3.7+)                    保序去重 / 字段顺序可依赖
改值安全,增删键要遍历副本           遍历修改纪律
Counter/defaultdict/dataclass       按场景升级选型

字典的进阶之路,和所有数据结构一样:先背熟「它的边界在哪」(浅合并、遍历修改、裸链),再把「专用变体」用在对应的场景里(Counter/defaultdict/dataclass)——普通 dict 是万能瑞士刀,但真正的高手知道什么时候该换专用工具。下一个项目里试试「把一个 dict 换成 dataclass」,那种 IDE 当场标红拼错的体验,会让你明白为什么结构化数据值得用结构。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

 

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

2541 篇文章

作家榜 »

  1. Pack 2541 文章
  2. 轩辕小不懂 2403 文章
  3. 小柒 2228 文章
  4. Nen 576 文章
  5. 王昭君 216 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章