python代数式的表达方式_关于python字典类型最疯狂的表达方式

一个Python字典表达式谜题

让我们探究一下下面这个晦涩的python字典表达式,以找出在python解释器的中未知的内部到底发生了什么。

# 一个python谜题:这是一个秘密

# 这个表达式计算以后会得到什么结果?

>>>{True: 'yes', 1: 'no', 1.0: 'maybe'}

有时候你会碰到一个很有深度的代码示例 --- 哪怕仅仅是一行代码,但是如果你能够有足够的思考,它可以教会你很多关于编程语言的知识。这样一个代码片段,就像是一个Zen kōan:一个在修行的过程中用来质疑和考验学生进步的问题或陈述。

译者注:Zen kōan,大概就是修行的一种方式,详情见wikipedia

我们将在本教程中讨论的小代码片段就是这样一个例子。乍看之下,它可能看起来像一个简单的词典表达式,但是仔细考虑时,通过cpython解释器,它会带你进行一次思维拓展的训练。

我从这个短短的一行代码中得到了一个启发,而且有一次在我参加的一个Python会议上,我还把作为我演讲的内容,并以此开始演讲。这也激发了我的python邮件列表成员间进行了一些积极的交流。

所以不用多说,就是这个代码片。花点时间思考一下下面的字典表达式,以及它计算后将得到的内容:

>>>{True: 'yes', 1: 'no', 1.0: 'maybe'}

在这里,我先等会儿,大家思考一下...

5...

4...

3...

2...

1...

OK, 好了吗?

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

>>>{True: 'yes', 1: 'no', 1.0: 'maybe'}

{True: 'maybe'}

我承认,当我第一次看到这个结果时,我很惊讶。但是当你逐步研究其中发生的过程时,这一切都是有道理的。所以,让我们思考一下为什么我们得到这个 - 我想说的是出乎意料 - 的结果。

这个子字典是从哪里来的

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

因此,当我们把它分解开的时候,我们的字典表达就相当于这个顺序的语句:

>>>xs = dict()

>>>xs[True] = 'yes'

>>>xs[1] = 'no'

>>>xs[1.0] = 'maybe'

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

>>>True == 1 == 1.0

True

OK,但在这里等一下。我确定你能够接受1.0 == 1,但实际情况是为什么True也会被认为等于1呢?我第一次看到这个字典表达式真的让我难住了。

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

“The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings ‘False’ or ‘True’ are returned, respectively.”

“布尔类型是整数类型的一个子类型,在几乎所有的上下文环境中布尔值的行为类似于值0和1,例外的是当转换为字符串时,会分别将字符串”False“或”True“返回。“(原文)

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

>>>['no', 'yes'][True]

'yes'

但为了代码的可读性起见,您不应该类似这样的来使用布尔变量。(也请建议你的同事别这样做)

Anyway,让我们回过来看我们的字典表达式。

就python而言,True,1和1.0都表示相同的字典键。当解释器计算字典表达式时,它会重复覆盖键True的值。这就解释了为什么最终产生的字典只包含一个键。

在我们继续之前,让我们再回顾一下原始字典表达式:

>>>{True: 'yes', 1: 'no', 1.0: 'maybe'}

{True: 'maybe'}

这里为什么最终得到的结果是以True作为键呢?由于重复的赋值,最后不应该是把键也改为1.0了?经过对cpython解释器源代码的一些模式研究,我知道了,当一个新的值与字典的键关联的时候,python的字典不会更新键对象本身:

>>>ys = {1.0: 'no'}

>>>ys[True] = 'yes'

>>>ys

{1.0: 'yes'}

当然这个作为性能优化来说是有意义的 --- 如果键被认为是相同的,那么为什么要花时间更新原来的?在最开始的例子中,你也可以看到最初的True对象一直都没有被替换。因此,字典的字符串表示仍然打印为以True为键(而不是1或1.0)。

就目前我们所知而言,似乎看起来像是,结果中字典的值一直被覆盖,只是因为他们的键比较后相等。然而,事实上,这个结果也不单单是由__eq__比较后相等就得出的。

等等,那哈希值呢?

python字典类型是由一个哈希表数据结构存储的。当我第一次看到这个令人惊讶的字典表达式时,我的直觉是这个结果与散列冲突有关。

哈希表中键的存储是根据每个键的哈希值的不同,包含在不同的“buckets”中。哈希值是指根据每个字典的键生成的一个固定长度的数字串,用来标识每个不同的键。(哈希函数详情)

这可以实现快速查找。在哈希表中搜索键对应的哈希数字串会快很多,而不是将完整的键对象与所有其他键进行比较,来检查互异性。

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

如果两个键具有相同的哈希值,那就称为哈希冲突(hash collision),这是在哈希表插入和查找元素时需要处理的特殊情况。

基于这个结论,哈希值与我们从字典表达中得到的令人意外的结果有很大关系。所以让我们来看看键的哈希值是否也在这里起作用。

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

classAlwaysEquals:

def__eq__(self,other):

return True

def__hash__(self):

return id(self)

这个类有两个特别之处。

第一,因为它的__eq__魔术方法(译者注:双下划线开头双下划线结尾的是一些Python的“魔术”对象)总是返回true,所以这个类的所有实例和其他任何对象都会恒等:

>>>AlwaysEquals() == AlwaysEquals()

True

>>>AlwaysEquals() == 42

True

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

True

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

>>>objects = [AlwaysEquals(),

AlwaysEquals(),

AlwaysEquals()]

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

[4574298968, 4574287912, 4574287072]

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

通过这个类,我们现在可以创建看上去与其他任何对象相同的对象,但它们都具有不同的哈希值。我们就可以通过这个来测试字典的键是否是基于它们的相等性比较结果来覆盖。

正如你所看到的,下面的一个例子中的键不会被覆盖,即使它们总是相等的:

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

{ : 'yes',

: 'no' }

下面,我们可以换个思路,如果返回相同的哈希值是不是就会让键被覆盖呢?

classSameHash:

def__hash__(self):

return 1

这个SameHash类的实例将相互比较一定不相等,但它们会拥有相同的哈希值1:

>>>a = SameHash()

>>>b = SameHash()

>>>a == b

False

>>>hash(a), hash(b)

(1, 1)

一起来看看python的字典在我们试图使用SameHash类的实例作为字典键时的结果:

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

{ : 'a',

: 'b' }

如本例所示,“键被覆盖”的结果也并不是单独由哈希冲突引起的。

Umm..好吧,可以得到什么结论呢?

检查python字典对象中两个 key 是否相同的条件是:二者的相等性(__eq__)以及hash值对比(__hash__)是否相等。那我们就来总结一下上述讨论的结果:

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

>>>True == 1 == 1.0

True

>>>(hash(True), hash(1), hash(1.0))

(1, 1, 1)

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

>>>{True: 'yes', 1: 'no', 1.0: 'maybe'}

{True: 'maybe'}

我们在这里涉及了很多方面内容,而这个特殊的python技巧起初可能有点令人难以置信 --- 所以我一开始就把它比作是Zen kōan。

如果很难理解本文中的内容,请尝试在Python交互环境中逐个去检验一下代码示例。你会收获一些关于python深处知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode】152. Maximum Product Subarray

题目:   Find the contiguous subarray within an array (containing at least one number) which has the largest product. For example, given the array [2,3,-2,4],the contiguous subarray [2,3] has the largest product 6. 题解: 先暴力解&am…

“哥德尔不完备定理”到底说了些什么?

来源: 赵昊彤科学网博客链接地址:http://blog.sciencenet.cn/blog-409681-1067019.html 【编者按:不知为何?一直不相信已有的数理、物理、生理、心理、管理……能够研究好人机融合智能系统。究其因,需要出现新的数/物…

ghost镜像浏览器_新电脑,GHOST装不进系统?不要急,跟我来

前几天,朋友转了台新电脑,用的是第十代CPU I3 10100,什么都安装好了,也按要求做了GPT分区,用GHOST安装了WIN10系统,可是重启时就是进不去,在BOOT选项里根本看不到硬盘。这是为什么呢&#xff1f…

如何卸载mysql server 2005_如何卸载SQL Server 2005

卸载SQL Server 2005的方法之一,放在这儿只是为了记住:1:把SQL Server2005的安装盘(安装文件)放入到光驱。2:打开如下路径:开始/运行,输入:cmd3:输入下列命令:Start /wai…

python异步消费kafka_Kafka 通过python简单的生产消费实现

使用CentOS6.5、python3.6、kafkaScala 2.10 - kafka_2.10-0.8.2.2.tgz (asc, md5) 一、下载kafka 下载地址 https://kafka.apache.org/downloads 里面包含zookeeper二、安装Kafka 1、安装zookeeper mkdir /root/kafka/ tar -vzxf kafka_2.10-0.8.2.2cd /root/kafka/kafka_2.10…

【技术趋势】2020 五大技术趋势:无人驾驶发展、机器视觉崛起、区块链实用化、人类增强技术、超自动化...

图源:https://unsplash.com/来源:AI开发者原标题:Here Is A Rundown of 5 Major Tech Trends Hitting 2020作者:| Richard Liu链接:https://medium.com/swlh/here-is-a-rundown-of-5-major-tech-trends-hitting-2020-6…

正则不能输入特殊字符_正则表达式语法学习和在线练习

标题: 正则表达式语法学习和在线练习作者: 梦幻之心星 sky-seekerqq.com标签: [#正则表达式,#语法,#学习,#练习]目录: [语法]日期: 2021-01-26背景说明正则表达式使搜索和替换操作更加灵活高效。许多程序设计语言都支持使用正则表达式进行字符串操作。正则表达式是由普通字符…

JavaScript Math 对象

// 返回算术常量 e,即自然对数的底数(约等于2.718)。 Math.E; // 2.718281828459045 // 返回圆周率(约等于3.14159)。 Math.PI; // 3.141592653589793 // 返回最低值。 Math.min(1, 2, 3, 4, 5, 6); // 1 // 返回最高值…

非接触物体尺寸形态测量_检修人必备的测量常识

小编今天给大家分享一下测量的常识,咱们搞机械的一定要懂点测量知识!一、测量器具的分类测量器具是一种具有固定形态、用以复现或提供一个或多个已知量值的器具。按用途的不同量具可分为以下几类:1. 单值量具只能体现一个单一量值的量具。可用…

生物战教训、生物安全问题以及未来监控军民两用生物技术扩散的手段

来源:美国空军国家安全研究学会研究报告2005年9月【知远导读】本篇推送编辑节选自美国空军国家安全研究学会2005年9月发布的一份题为《生物战教训、生物安全问题以及未来监控军民两用生物技术扩散的手段》的研究报告。该报告直接来源于作者海伦普凯特(He…

python关系运算符和逻辑运算符的优先级_python中逻辑运算符的优先级问题

遇到的问题今天做题的时候,碰到一个关于逻辑运算符优先级的问题,看到之后我懵了0 and 12 and 30 or 12 or 3上面的返回值是什么?我一开始以为返回的都是左边的值,但是结果和我想的不同,结果如下:In [4]: 0 …

编程面试题之——简答题(持续更新...)

简答题: 1、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后? 答:会执行,在方法返回调用者前执行。注意:在finally中改变返回值…

如何避免字符串混淆加密_iOS-代码混淆加固方案

对于iOS来说,由于系统是封闭的,APP上架需要通过App Store,安全性来说相当高。但是对于大厂和知名APP而言,别人给的安全保障永远没有自己做的来得踏实。所以对于大厂、少部分企业级和金融支付类应用来说加固是相当重要的。下面是目…

DARPA计划在2021年开展多种新型武器概念研究

来源:中国指挥与控制学会“远射”项目DARPA计划于2021年投资2200万美元启动“远射”项目,演示一种空射武器系统。该系统由速度较慢的远程飞行器搭载至战区,在战区上空发射多枚空空导弹来实施作战。该武器可由现有战斗机外部挂载,或…

python算法实现源码_Python实现七个基本算法

1.顺序查找当数据存储在诸如列表的集合中时,我们说这些数据具有线性或顺序关系。 每个数据元素都存储在相对于其他数据元素的位置。 由于这些索引值是有序的,我们可以按顺序访问它们。 这个过程产实现的搜索即为顺序查找。顺序查找原理剖析:从…

多重边框

div {box-shadow: 0 0 0 6px rgba(0, 0, 0, 0.2), 0 0 0 12px rgba(0, 0, 0, 0.2), 0 0 0 18px rgba(0, 0, 0, 0.2), 0 0 0 24px rgba(0, 0, 0, 0.2); height: 200px; margin: 50px auto; width: 400px } 转载于:https://www.cnblogs.com/yk-ontheway/p/6737698.html

python词云设计实例_python词云库wordcloud的使用方法与实例详解

wordcloud是优秀的词云展示第三方库一、基本使用 import jieba import wordcloud txt open("1.txt", "r", encodingutf-8).read() words jieba.lcut(txt) txt_1 " ".join(words) # print(txt1) w wordcloud.WordCloud(font_path"msyh.t…

细胞因子风暴与新冠肺炎

来源:陈辉科学网博客链接地址:http://blog.sciencenet.cn/blog-3426569-1219679.html 2020年2月15日下午,在国务院联发联控机制新闻发布会上,周琪院士介绍说“炎症因子风暴”[作者注释:即是细胞因子风暴(Cy…

mysql 启动 修改密码_基础的启动/停止/重启/密码修改MySQL

如何启动/停止/重启MySQL一、启动方式1、使用 service 启动:service mysqld start2、使用 mysqld脚本启动:/etc/inint.d/mysqld start3、使用 safe_mysqld启动:safe_mysqld&二、停止1、使用 service 启动:service mysqldstop2…

预编译对象解决SQL注入问题

转载于:https://www.cnblogs.com/suanshun/p/6739454.html