查看: 3711|回复: 3

Python字典get方法实现频次统计与安全取

[复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式
Python字典用d[key]取值时,键不存在会抛出KeyError,这是频次统计、配置读取和嵌套字典访问中常见的出错点。dict.get()的价值是容错取值:键存在返回对应值,键不存在返回指定默认值,不修改字典,也不自动创建键。基本形式为dict.get(key, default=None),key是待查找键,default可选。

一、get与直接下标的区别
  1. d = {'name': 'Tom', 'age': 18}
  2. print(d['name'])  # Tom
  3. # print(d['gender'])  # KeyError: 'gender'
  4. print(d.get('name'))  # Tom
  5. print(d.get('gender'))  # None
  6. print(d.get('gender', '未知'))  # 未知
复制代码

直接下标要求键必须存在;get在键缺失时返回默认值。因此,配置读取可写成config.get('port', 8080),替代先判断if 'name' in d再取值的写法。

二、用get做频次统计

计数场景的核心是count[w] = count.get(w, 0) + 1:先取当前键的计数,缺失时按0处理,再加1写回。示例:
  1. words = ['a', 'b', 'a', 'c', 'a']
  2. count = {}
  3. for w in words:
  4.     count[w] = count.get(w, 0) + 1
  5. print(count)  # {'a': 3, 'b': 1, 'c': 1}
复制代码

分组场景可以用setdefault(k, []).append(v),原文也提到可配合get。嵌套字典链式访问时,用user.get('info', {}).get('name', '未知')可避免中间层缺失导致异常。

三、实用案例:统计上榜大学的国家与数量

原文案例读取data.txt,每行格式为排名、学校名称、国家,字段用逗号分隔;程序跳过字段不足3个的行,以国家为键,把学校名称收集到列表中,再按国家上榜大学数量降序输出。关键语句dic[i[-1]] = dic.get(i[-1], []) + [i[1]]的含义是:以i[-1]国家为键,取出已有学校列表,不存在时用空列表,再拼接当前学校i[1]并写回字典。完整代码:
  1. f = open('data.txt', 'r', encoding='utf-8')
  2. dic = {}
  3. for line in f:
  4.     i = line.strip().split(',')
  5.     if len(i) < 3:
  6.         continue
  7.     dic[i[-1]] = dic.get(i[-1], []) + [i[1]]
  8. unis = list(dic.items())
  9. unis.sort(key=lambda x: len(x[1]), reverse=True)
  10. for d in unis:
  11.     print('{:>4}: {:>4} : {}'.format(d[0], len(d[1]), ','.join(d[1])))
复制代码

这段代码中,i[-1]取国家字段,i[1]取学校名称,len(i) < 3用于过滤不完整记录;list(dic.items())把字典转为可排序的列表,sort的key=lambda x: len(x[1])按学校列表长度排序,reverse=True表示降序;输出时len(d[1])是国家上榜学校数,','.join(d[1])把学校名称用逗号连接。若数据量较大,这种每次拼接新列表的写法逻辑直观,但会频繁创建列表,实际项目可关注开销。

四、注意事项

get()不会修改字典,键不存在时也不会自动添加:d = {}时d.get('x', 10)返回10,但d仍为{}。需要不存在则添加时用setdefault,例如d.setdefault('x', 10)后d变为{'x': 10}。默认值只在键缺失时返回;如果键存在但值为None,d.get('x', 100)返回None而不是100。列表、集合等对象没有字典的get方法,列表的index语义也不同。requests的GET请求、Queue的get()、Tkinter变量的get()等属于不同类的同名方法,语义各异,不要与字典get混用。

五、选择建议

确定键存在时可直接用d[key];键可能不存在时用d.get(key, default);需要不存在则添加时用d.setdefault(key, default)。get()的本质是容错取值,适合配置读取、计数、分组和嵌套字典安全访问等场景。
回复

使用道具 举报

发表于 5 天前 | 显示全部楼层

Re: Python字典get方法实现频次统计与安全取

这帖把 dict.get 的边界讲得挺清楚,尤其是“键存在但值为 None 时仍返回 None,而不是默认值”这一点,很多人第一次用会踩坑。频次统计那段 count = count.get(w, 0) + 1 是经典写法,逻辑直观,也比先判断 in 再取值简洁。 案例部分用列表收集学校名称、再按数量降序输出,示例完整;楼主自己也点出了每次拼接新列表的开销,这个提醒很实在。如果只关心数量,用 get 加一就够;要保留名单时再考虑别的结构。 另外,过滤字段不足 3 行的写法简单有效,实际数据里如果有空行或表头,可能还得额外判断一下,不过作为示例已经很清楚了。 想请教下:嵌套访问时用 user.get('info', {}).get('name', '未知'),如果中间层存在但不是字典,比如是个字符串,还是会报错。这种一般怎么处理比较稳妥?
回复 支持 反对

使用道具 举报

发表于 5 天前 | 显示全部楼层

Re: Python字典get方法实现频次统计与安全取

讲得很系统,尤其是把 get 和直接下标、setdefault 三者的适用场景分开说,这点对新手很实用。频次统计那个 count = count.get(w, 0) + 1 的写法我也一直在用,读起来比先判断键是否存在再加减要顺。 补充两个自己踩过的点。一是默认值如果传的是可变对象要留个心眼,像 get(k, []) 每次调用都会新建一个空列表,所以安全;但如果是提前定义好的一个共享列表当默认值传进去,后续往里 append 就会污染这个共享对象,这个坑和函数默认参数是同一类。二是楼主最后提到大数据量下反复拼接列表有开销,我一般会改成 setdefault 取出列表后直接 append,或者干脆用 collections.defaultdict(list),代码更短也更省,逻辑上跟原文那种拼接写法是等价的。 嵌套字典链式 get 那段也很实用,我平时读配置就经常写这种链式,比一层层判断省事,只是层级深了可读性会下降,超过三层我一般会抽个小函数封装一下。整体这篇从原理到案例再到注意事项脉络很清楚,收藏了。
回复 支持 反对

使用道具 举报

发表于 5 天前 | 显示全部楼层

Re: Python字典get方法实现频次统计与安全取

楼主这篇把 get 的边界讲得挺细的,尤其是“键存在但值为 None 时返回 None 而不是默认值”和“列表/Queue/requests 的同名 get 语义不同”这两条,很多教程都容易漏掉。我在实际写的时候还有几个补充点,顺手聊一下: 一是计数场景,get(w, 0) + 1 是最直观的写法,但如果只是纯计数、分组,标准库里其实有更省事的工具:Counter 可以直接 most_common() 拿到降序结果,defaultdict(list) 也能省掉每次 get 再写回。用 get 的好处是逻辑外显、不引入额外依赖,学习阶段很合适,工程里可以按团队习惯选。 二是 setdefault 那个坑值得单独提一句:d.setdefault(k, []) 里的 [] 每次调用都会先被创建出来,即使键已经存在,所以放在大循环里会有无谓的对象创建开销。而 get(k) 再判断的写法反而没有这个问题,两者性能取舍跟楼里“每次拼接新列表会频繁创建列表”其实是同一类现象。 三是嵌套字典链式访问,user.get('info', {}).get('name', '未知') 的前提是 info 缺失,但如果 info 存在而值是 None,第二步就会变成 None.get 直接报 AttributeError。稳妥点的写法是 (user.get('info') or {}).get('name'
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-27 17:23 , Processed in 0.028265 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部