当前位置: 首页 > news >正文

Python 字典和集合(常见的映射方法)

本章内容的大纲如下:
常见的字典方法
如何处理查找不到的键
标准库中 dict 类型的变种set 和 frozenset 类型
散列表的工作原理
散列表带来的潜在影响(什么样的数据类型可作为键、不可预知的
顺序,等等)

常见的映射方法

映射类型的方法其实很丰富。表 3-1 为我们展示了
dict、defaultdict 和 OrderedDict 的常见方法,后面两个数据类型
是 dict 的变种,位于 collections 模块内。

表3-1:dict、collections.defaultdict和
collections.OrderedDict这三种映射类型的方法列表(依然省略
了继承自object的常见方法);可选参数以[…]表示

image

  • default_factory 并不是一个方法,而是一个可调用对象(callable),它的值在
    defaultdict 初始化的时候由用户设定。

#OrderedDict.popitem() 会移除字典里最先插入的元素(先进先出);同时这个方法还有一
个可选的 last 参数,若为真,则会移除最后插入的元素(后进先出)。

上面的表格中,update 方法处理参数 m 的方式,是典型的“鸭子类
型”。函数首先检查 m 是否有 keys 方法,如果有,那么 update 函数就
把它当作映射对象来处理。否则,函数会退一步,转而把 m 当作包含了
键值对 (key, value) 元素的迭代器。Python 里大多数映射类型的构造
方法都采用了类似的逻辑,因此你既可以用一个映射对象来新建一个映
射对象,也可以用包含 (key, value) 元素的可迭代对象来初始化一个
映射对象。

在映射对象的方法里,setdefault 可能是比较微妙的一个。我们虽然
并不会每次都用它,但是一旦它发挥作用,就可以节省不少次键查询,
从而让程序更高效。如果你对它还不熟悉,下面我会通过一个实例来讲
解它的用法。

用setdefault处理找不到的键
当字典 d[k] 不能找到正确的键的时候,Python 会抛出异常,这个行为
符合 Python 所信奉的“快速失败”哲学。也许每个 Python 程序员都知道
可以用 d.get(k, default) 来代替 d[k],给找不到的键一个默认的
返回值(这比处理 KeyError 要方便不少)。但是要更新某个键对应的值的时候,不管使用 getitem 还是 get 都会不自然,而且效率
低。就像示例 3-2 中的还没有经过优化的代码所显示的那
样,dict.get 并不是处理找不到的键的最好方法。

示例 3-2 是由 Alex Martelli 举的一个例子 变化而来,例子生成的索引
跟示例 3-3 显示的一样。

示例 3-2 index0.py 这段程序从索引中获取单词出现的频率信
息,并把它们写进对应的列表里(更好的解决方案在示例 3-4 中)

"""创建一个从单词到其出现情况的映射"""
import sys
import re
WORD_RE = re.compile(r'\w+')
index = {}
with open(sys.argv[1], encoding='utf-8') as fp:
  for line_no, line in enumerate(fp, 1):
    for match in WORD_RE.finditer(line):
    word = match.group()
    column_no = match.start()+1
    location = (line_no, column_no)
# 这其实是一种很不好的实现,这样写只是为了证明论点
occurrences = index.get(word, []) ➊
occurrences.append(location) ➋
index[word] = occurrences ➌
# 以字母顺序打印出结果
for word in sorted(index, key=str.upper): ➍
    print(word, index[word])

❶ 提取 word 出现的情况,如果还没有它的记录,返回 []。
❷ 把单词新出现的位置添加到列表的后面。
❸ 把新的列表放回字典中,这又牵扯到一次查询操作。
❹ sorted 函数的 key= 参数没有调用 str.uppper,而是把这个方法
的引用传递给 sorted 函数,这样在排序的时候,单词会被规范成统一
格式。

示例 3-3 这里是示例3-2 的不完全输出,每一行的列表都代表一
个单词的出现情况,列表中的元素是一对值,第一个值表示出现的
行,第二个表示出现的列

$ python3 index0.py ../../data/zen.txt
a [(19, 48), (20, 53)]
Although [(11, 1), (16, 1), (18, 1)]
ambiguity [(14, 16)]
and [(15, 23)]
are [(21, 12)]
aren [(10, 15)]
at [(16, 38)]
bad [(19, 50)]
be [(15, 14), (16, 27), (20, 50)]
beats [(11, 23)]
Beautiful [(3, 1)]
better [(3, 14), (4, 13), (5, 11), (6, 12), (7, 9), (8, 11),
(17, 8), (18, 25)]
...

示例 3-2 里处理单词出现情况的三行,通过 dict.setdefault 可以只
用一行解决。示例 3-4 更接近 Alex Martelli 自己举的例子。

示例 3-4 index.py 用一行就解决了获取和更新单词的出现情况列
表,当然跟示例 3-2 不一样的是,这里用到了 dict.setdefault

"""创建从一个单词到其出现情况的映射"""
import sys
import re
WORD_RE = re.compile(r'\w+')
index = {}
with open(sys.argv[1], encoding='utf-8') as fp:
    for line_no, line in enumerate(fp, 1):
      for match in WORD_RE.finditer(line):
      word = match.group()
column_no = match.start()+1
      location = (line_no, column_no)
      index.setdefault(word, []).append(location) ➊
# 以字母顺序打印出结果
for word in sorted(index, key=str.upper):
    print(word, index[word])

➊ 获取单词的出现情况列表,如果单词不存在,把单词和一个空列表
放进映射,然后返回这个空列表,这样就能在不进行第二次查找的情况
下更新列表了。

也就是说,这样写:

my_dict.setdefault(key, []).append(new_value)

跟这样写:

if key not in my_dict:
my_dict[key] = []
my_dict[key].append(new_value)

二者的效果是一样的,只不过后者至少要进行两次键查询——如果键不
存在的话,就是三次,用 setdefault 只需要一次就可以完成整个操
作。

那么,在单纯地查找取值(而不是通过查找来插入新值)的时候,该怎
么处理找不到的键呢?

相关文章:

  • 【学Rust写CAD】39 over_in_in 函数(alpha256补充方法)
  • JS中的Promise对象
  • 源代码保密解决方案
  • linux上todesk无法使用问题
  • 避免误用strncmp与memcmp,strcpy与memcpy
  • CSS中的inline-flex与flex的区别
  • 在C++11及后续标准中,auto和decltype是用于类型推导的关键特性,它们的作用和用法。
  • 力扣热题100刷题day62|283.移动零、39.组合总和、94.二叉树的中序遍历
  • 百度开放平台调用动物识别接口
  • 运营商在网状态查询API:精准探测手机号的状态
  • LLM Agent未来研究趋势
  • 前后端开发规范
  • 好数(蓝桥杯2024省赛B组)
  • Win11重新设计开始菜单 变成iOS样式
  • 【Linux】Git的简单使用
  • 刷题 | 牛客 - js简单10题(更ing)1/10知识点解答
  • pdf转latex
  • 关于GEO的100个核心问题
  • Linux中进程
  • 微服务注册中心选择指南:Eureka vs Consul vs Zookeeper vs Nacos
  • 公司怎么申请免费做网站/怎样在百度上发表文章
  • 两学一做专题网站用途/郑州seo线下培训
  • 沈阳专业的网站设计公司/游戏推广拉人渠道
  • 竭诚网络网站建设价格/百度人工服务24小时电话
  • 个人网站数据库怎么做/西安危机公关公司
  • 模仿别人的网站/百度指数的使用方法