当前位置:首页 > 娱乐星闻

疯狂字典 疯狂的Python字典

密切注意

原文:丹·巴德译者:维密克斯

丹·巴德(Dan Bader)的一篇有趣的博文,让我们学习一下如何研究一个意想不到的Python现象。一个Python字典表达式难题

让我们探索下面这个晦涩难懂的Python字典表达式,看看Python解释器内部发生了什么。

#一个python难题:

#这个表达式计算出来后会是什么结果?

>。>。>。{True:'是',1:'否',1.0:'可能' }

有时候你会遇到一个很深的代码例子,哪怕只是一行代码,但是如果你想的足够多,它可以教会你很多关于编程语言的知识。

这样的代码片段就像一个禅宗的Kan:用来质疑和检验学生在修行过程中的进步的问题或语句。(译者注:禅宗可能是一种修行方式,详见维基百科)

我们将要讨论的代码片段就是这样一个例子。乍一看,它可能看起来像一个简单的字典表达式,但当你仔细想想,它会通过cpython解释器给你一个思维发展的训练。

我从这一小段代码中获得了灵感,有一次在我参加的一个Python会议上,我把它作为我演讲的内容,并以它开始我的演讲。

这也激发了我的python邮件列表成员之间的积极交流。

所以不用说,这就是代码芯片。花点时间想想下面的字典表达式,计算后会得到什么:

>。>。>。{True:'是',1:'否',1.0:'可能' }

在这里,我再等一会,大家好好想想…

5…

4…

3…

2…

1…

好的,你准备好了吗?

这是在cpython解释器的交互界面中计算上述字典表达式的结果:

>。>。>。{真:'是',1:'不是',1.0:'可能' }

{正确:“可能”}

我承认我第一次看到这个结果的时候很惊讶。但是当你逐渐研究这个过程的时候,一切都有了意义。

所以,让我们想想为什么我们会得到这个——我想说的是意想不到的——结果。

这本子词典是从哪里来的?

当python处理我们的字典表达式时,它首先构造一个新的空字典对象。然后按照字典表达式给定的顺序分配键和值。

因此,当我们分解它时,我们的字典按以下顺序表达句子:

>。>。>。xs = dict()

>。>。>。xs[True] = 'yes '

>。>。>。xs[1] = 'no '

>。>。>。xs[1.0] = '可能'

奇怪的是,Python认为这个例子中使用的所有字典键都是相等的

>。>。>。True== 1== 1.0

真正的

好的,但是在这儿等着。我肯定你能接受1.0 == 1,但事实是,为什么真也认为等于1?第一次看到这种字典式的表达,真的很困惑我。

在python文档中做了一些探索之后,我发现python使用bool作为int类型的子类。这是Python 2和Python 3的片段:

布尔类型是整数类型的一个子类型,在几乎所有上下文中,布尔值的行为分别类似于值0和1,唯一的例外是当转换为字符串时,将分别返回字符串“假”或“真”

“布尔类型是整数类型的一个子类型。在几乎所有上下文中,布尔值的行为类似于值0和1,只是当转换为字符串时,将分别返回字符串“假”或“真”。

是的,这意味着您可以在编程时使用布尔值作为Python中列表或元组的索引:

>。>。>。['否','是'][真]

“是”

但是为了可读性,不应该这样使用布尔变量。也请建议你的同事不要这样做

不管怎样,让我们回顾一下我们的字典表达式。

在python中,True、1和1.0都表示同一个字典键。当解释器计算字典表达式时,它会重复覆盖键“真”的值。这解释了为什么生成的字典只包含一个键。

在我们继续之前,让我们回顾一下最初的字典表达式:

>。>。>。{真:'是',1:'不是',1.0:'可能' }

{正确:“可能”}

为什么这里的最终结果以真为关键?由于重复赋值,最后键不应该改成1.0?

在研究了CPpython解释器源代码的一些模式后,我知道当一个新的值与字典关键字相关联时,python字典不会更新关键字对象本身:

>。>。>。ys = {1.0:'否' }

>。>。>。ys[真] = '是'

>。>。>。屈服强度

{1.0:'是' }

当然,这作为一个性能优化是有意义的——如果键被认为是相同的,为什么要花时间更新原来的呢?

在最初的例子中,您还可以看到原始的True对象从未被替换。因此,字典的字符串表示仍然以“真”作为键打印(而不是1或1.0)。

据我们所知,结果中的字典值似乎总是被覆盖,只是因为它们的键在比较后是相等的。但是,其实这个结果并不是只有__eq__比较后相等才得到的。

等等,哈希值呢?

Python字典类型由哈希表数据结构存储。当我第一次看到这个神奇的字典表达式时,我的直觉是,结果与哈希冲突有关。

哈希表中的关键字根据每个关键字的哈希值存储在不同的“桶”中。哈希值是指根据每个字典的关键字生成的固定长度的数字字符串,用于识别每个不同的关键字。

这样可以快速搜索。与其将完整的密钥对象与所有其他密钥进行比较来检查异构性,不如在哈希表中搜索与密钥相对应的哈希数字符串要快得多。

然而,哈希值的计算方法通常并不完美。而且,实际上,两个或多个不同的键会生成相同的哈希值,它们最终会出现在同一个哈希表中。

如果两个密钥的哈希值相同,则称为哈希冲突,这是在哈希表中插入和搜索元素时需要处理的特殊情况。

基于这个结论,哈希值与我们从字典表达式中得到的意外结果有很大关系。那么我们来看看这个键的哈希值在这里是否也有效。

我定义了这样一个类作为我们的测试工具:

classAlwaysEquals:

def__eq__(自我,其他):

返回真

def__hash__(self):

returnid(自我)

这个类有两个特点。

首先,因为它的__eq__ magic方法总是返回true,所以这个类和任何其他对象的所有实例都是相等的:

>。>。>。AlwaysEquals() == AlwaysEquals()

真正的

>。>。>。AlwaysEquals() == 42

真正的

>。>。>。AlwaysEquals() == 'waaat?'

真正的

其次,每个Alwaysequals实例还将返回由内置函数id()生成的唯一哈希值:

>。>。>。objects = [AlwaysEquals(),

AlwaysEquals(),

AlwaysEquals()]

>。>。>。[hash(obj)for object in objects]

[4574298968, 4574287912, 4574287072]

在CPython中,id()函数返回内存中一个对象的地址,这个地址肯定是唯一的。

有了这个类,我们现在可以创建看起来和其他对象一样的对象,但是它们都有不同的哈希值。我们可以使用它来测试字典键是否基于它们的相等比较结果而被覆盖。

如您所见,以下示例中的键不会被覆盖,即使它们总是相等的:

>。>。>。{AlwaysEquals(): 'yes ',AlwaysEquals(): 'no'}

{ & lt位于0x110a3c588 >的AlwaysEquals对象。:'是',

& lt位于0x110a3cf98 >的AlwaysEquals对象。:' no'}

现在,我们可以改变我们的想法。如果返回相同的哈希值,密钥会被覆盖吗?

classSameHash:

def__hash__(self):

返回1

SameHash类的这个实例彼此不同,但是它们具有相同的哈希值1:

>。>。>。a = SameHash()

>。>。>。b = SameHash()

>。>。>。a == b

假的

>。>。>。哈希(a),哈希(b)

(1, 1)

当我们尝试使用SameHash类的一个实例作为字典关键字时,让我们看看python字典的结果:

>。>。>。{a: 'a ',b: 'b'}

{ & lt0x7f7159020cb0 >处的SameHash实例;:' a ',

& lt0x7f7159020cf8 >处的SameHash实例;:' b'}

如本例所示,“密钥覆盖”的结果并不仅仅是由哈希冲突引起的。

嗯...那么,可以得出什么结论呢?

Python字典中的键是否相同(只有相同才会覆盖)取决于两个条件:

1,两个值是否相等(compare __eq__ method)。

2.比较它们的哈希值是否相同(compare _ _ hash _ _ method)。

让我们试着总结一下我们的研究结果:

{true:'是',1:'否',1.0:'可能' }

字典表达式的计算结果为{true:'可能' },因为键true、1和1.0都相等,并且它们都具有相同的哈希值:

>。>。>。True== 1== 1.0

真正的

>。>。>。(哈希(真)、哈希(1)、哈希(1.0))

(1, 1, 1)

`

也许不那么令人惊讶,这就是为什么我们得到这个结果作为字典的最终结果:

>。>。>。{True:'是',1:'否',1.0:'可能' }

{正确:“可能”}

我们在这里已经涵盖了许多方面,这种特殊的python技能起初可能有点不可思议——所以我在一开始将其与Zen kAn进行了比较。

如果本文内容难以理解,请尝试在Python交互环境下逐一查看代码示例。你会对python有一些深入的了解。

原文链接:https://dbader.org/blog/python-mystery-dict-expression

翻译链接:http://vimiix . com/post/2017/12/28/python-神秘学-dict-expression/

1.《疯狂字典 疯狂的Python字典》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《疯狂字典 疯狂的Python字典》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/1161259.html

上一篇

表语从句是什么

下一篇

主语从句是什么

张家口化工厂燃爆事故一审宣判 该案宣判结果是什么

张家口化工厂燃爆事故一审宣判 该案宣判结果是什么

河北盛华化工有限公司25日一审宣判,12名被告人在生产经营中违反相关安全管理规定,导致事故发生,12名被告人均构成重大责任事故罪。其中11人被判处5至3年徒刑,1人免于刑事处罚。网友热;梦想:法规是人制定的!句子太轻,Exchangefocus...

慕残者论坛 让我们一起来了解慕残!

慕残者论坛 让我们一起来了解慕残!

这个群体只喜欢残疾人。 来源|通往残疾之路  你知道世界上还有一个群体叫Mucan吗? 这个群体只喜欢残疾人。 顺带一提,Mucan官方解释:奉献者是一种审美观念的认知,一般来说是异性身体的审美观念。 主要是指在当前主流社会的审美观念是四肢为美...

摩拜状告滴滴车锁 滴滴车锁怎么了状告之后什么结果

近日,北京市知识产权法院受理了北京摩比克科技有限公司(以下简称摩比克公司)诉北京小菊科技有限公司(以下简称小菊公司)和杭州轻骑科技有限公司(以下简称轻骑公司)侵犯发明专利权纠纷案,依法查封、扣押了小菊公司和轻骑公司在北京经营的绿橙自行车和小蓝自...

操场埋尸彻底清查 操场埋尸案案情经过是判决结果是什么

操场埋尸彻底清查 操场埋尸案案情经过是判决结果是什么

近日,杜及其同伙罗广忠被依法逮捕,并以故意杀人罪被起诉。经过16年的等待,邓世平一家等待正义,正义终于可以战胜邪恶。扫黑除恶,安抚人心。2019年4月中旬,新晃县公安局在专项扫黄行动中查获杜涉恶犯罪团伙,广泛收集社会线索。5月,怀化市公安局在检...

厦门导游威胁游客 怎么威胁的事情结果是什么

厦门导游威胁游客 怎么威胁的事情结果是什么

11月23日,厦门导游威胁游客的视频在网上传播,引起网友关注。视频中,一名中年女导游不断威胁一名男子,大喊:“到了鼓浪屿还这么嚣张!在岛上你信不信?你不能出去!”据视频发布者称:“交导游费不买东西就是这样的态度。”11月25日,厦门鼓浪屿文化旅...

操场埋尸彻底清查 清查结果怎么样警方怎么说

2019年4月中旬,新晃县公安局在专项扫黄行动中查获杜涉恶犯罪团伙,广泛收集社会线索。5月,怀化市公安局在检查中央扫黄打非十六督察队交办的邓世平杀人案线索时,发现杜与此案有很大关联。经深入调查,根据杜、罗广忠的供述和现场鉴定,公安机关于6月20...

湖人vs鹈鹕 具体什么情况比赛结果如何

湖人vs鹈鹕 具体什么情况比赛结果如何

11月27日,湖人将于北京时间28日10: 30客场挑战鹈鹕。浓眉哥今年夏天交易后第一次回到新奥尔良,詹姆斯带领湖人取得九连胜。“这将是一场完全不同的比赛,但你必须拥抱它。”粗眉哥说:“我知道当时球迷的反应,但是回到这个球场,以对手的身份对阵鹈...

复盘最强医保谈判  什么是医保谈判谈判结果怎么样

复盘最强医保谈判 什么是医保谈判谈判结果怎么样

“我每天都带着我的戒指。11月11日监测数据显示压力全天呈红色。它一整天都在高压下持续11个小时。”吉林省社会医疗保险管理局副局长刘洪亮说,不是双11抢到了红包,而是他参加医保价格谈判第一天的感受。刘洪亮是在11月28日国家健康险局在北京召开的...