《Fluent Python》第三章Dictionaries and Sets

即使用户的程序代码没有明确的使用字典,但在任何运行的Python程序可能有多个字典同时工作。

                                                                                                  — A. M. Kuchling

            (18章,《“Python’s Dictionary Implementation》)

dict字典类型不仅广泛的应用于我们的代码中,还是Python应用的基础部分。模块命名空间,类,实例属性和函数关键字参数是字典中的基本结构部署。内置函数在__builtins__.__dict__中。

由于它们扮演的关键角色,Python的dict才能被很好的充分利用。Python高性能的dict背后的引擎是哈希表。

我们也会在本章中谈一谈集合set,它也是由哈希表完成的。了解哈希表是如何工作的会成为最大程度利用字典和集合的关键。

本章提要:

  • 常规字典方法
  • 对缺失键的特殊处理
  • 在标准库中的字典变化
  • 集合和原封集合类型
  • 哈希表如何工作

  • 哈希表的含义(密钥类型限制,不定排序等)


通用映射类型

collections.abc模块提供了映射和可变映射ABCs到形式化了字典和相关类型的接口。看图3.1:


特殊的映射实现通常扩展了dict或者collections.UserDict,而不是这些ABCs。ABCs的主要价值是记录映射的最小接口,和作为在需要广义范围内支持映射的代码中的isinstance测试的准则:


因为可替代的映射类型可以被使用,所以isinstance在检查一个函数自变量是否为字典类型上会更好。

在标准库中所有映射类型都由基本字典基本构成,所以它们的共享秘钥是由限制的(哈希值不需要成为可哈希的只有秘钥需要)。


What Is Hashable?

在python Glossary中有关与hashable的定义:

如果一个对象在其生命周期中哈希值不变(通过__hash__方法),而且可以和其他对象相比较(通过__eq__()方法)则称其为可哈希的。相同的可哈希的对象必须有相同的哈希值。

在原子级不可变的类型中(str,bytes,numeric类型)均为可哈希的。不可变集合中通常是可哈希的,因为通过定义它的元素必须是可哈希的。一个元组是可哈希的只有在其所有项均为可哈希的情况下。可参考元组tt,tl和tf:


在撰写本书时,python Glossary指出:“Python中不可变的内置对象是可哈希的”,但是这在某种情况下是错误的,如一个元组是b不可变的,但是它可能包含涉及不可哈希的对象。

用户自定义的类型均默认为可哈希的,这是由于它的哈希值就是id()而且他们都是不等的。如果一个对象执行了可以考虑其内部状态的__eq__函数,那么只有当所有属性均为不可变的才可能是可哈希的。

基于这些规则,可以通过集中方法构建字典。在库引用中的类型页展示了建立字典的几种方法:


除了文字型语法和复杂的字典构造器,我们可以使用字典理解去建立,详见下一节

dict Comprehensions

在Python2.7中,listcomps 和genexps的语法被运用在字典理解中(关于集合的理解也是如此,我们即将学习到)。dictcomp是通过从任意迭代器中产生键:值对来创建一个字典。在3-1的例子中显示了利用字典理解从两个相同的元组序列去构建两个字典。


如果你是惯于使用listcomps,那对dictcomps也不陌生。如果不是,listcomps语法的传播意味着他比以往都要流行。

现在让我们对映射做一个全面解析。

Overview of Common Mapping Methods(常规映射方法概述)

映射的基础接口十分丰富。表3-1展示了通过字典执行的方法和两个最有用的变形:defaultdict和OrderedDict,两个都在collections模块中有定义。


更新处理第一个参数m最基本的方法就是duck类型:它首先检查了m是否有键方法,如果有就假设这是一个映射,否则,更新回到迭代m。大多数Python的构造函数使用的是内部更新的逻辑,这意味着它可以从其他映射初始化或者它可以从任何一个迭代对象产生(键,值)对。

一个巧妙的映射方法就是setdefault,我们并不是总是需要它,但当我们这么做事,它通过避免冗余键查找提供了显著的速度提升,下一节我们会通过一个例子来说明如何使用它。

Handling Missing Keys with setdefault

与快速故障哲学相一致,当k不存在时,dict 访问d[k]会报错。pythonista中的d.get(k,default)是可以替代d[k]的,而且无论何时设置一个默认值都比报keyError的错要好。然而,当更新值时(如果它是可变的)会发现无论是使用__getitem__或者get都是效率十分低下的。思考下面的例3-2.当dict.get不是最优方法去解决缺失键默认值时,一个显示实例的次优脚本。




在实例3-2中处理事件的三行可以被单行使用dict.setdefault语句替代。实例3-4十分接近Alex Martelli的原始案例。



一个相关问题是在查找(不仅仅是插入时)时处理缺失值是下一节的主题。

Mappings with Flexible Key Lookup


(本文翻译自英文原版《fluent Python》第63-70页)

本人翻译水平有限,仅限参考,如有错误,欢迎指出。


                                                                                           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值