python进阶(第三章2)字典和集合

文章目录

    • 3.8 集合论
          • nee中的元素在haystack中出现的次数,可以在任何可迭代对象上
      • 3.8.1集合字面量
      • 3.8.2 集合推导
      • 3.8.3 集合操作
    • 3.9 dict和set的背后
      • 3.9.1 一个关于效率的实验
      • 3.9.2 字典中的散列表
        • 1.散列值和相等性
        • 2.散列表算法
          • 获取值:
          • 添加新的元素
          • 更新现有的键值
      • 3.9.3 dict的实现及其导致的结果
        • 1.键必须是可散列的
          • 所有用户自定义的对象默认都是可散列的,因为它们的散列值由id()值获取,而且都是不相等的。
        • 2.字典在内存上的开销巨大
        • 3.键查询很快
        • 4.键的次序取决于添加顺序
        • 5.往字典里添加新键可能会改变已有键的顺序
      • 3.9.4 set的实现以及导致的结果

3.8 集合论

集合的本质是许多唯一对象的聚集。一次,集合可以用于去重。
集合中的元素必须是可散列的,set类型本身是不可散列的,但是frozenset可以。因此可以创建一个包含不同frozenset的set.

  • 什么叫做可散列的呢?“python里所有不可变类型都是可散列的”。
    除了保证唯一性,集合还实现了很多基础的中缀表达式
中缀运算符含义
a&b返回它们的交集
ab
a-b返回它们的差集
nee中的元素在haystack中出现的次数,可以在任何可迭代对象上
found = len(set(nee) & set(haystack))
或者
found = len(set(nee).intersection(haystack))

除了快速的查找功能(归功于背后的散列表),内置的set和frozenset提供了额丰富的功能和操作。

3.8.1集合字面量

{1},{1,2,3}和数学形式一模一样

3.8.2 集合推导

例子:

>>> from unicodedata import name
>>> {chr(i) for i in range(32,256) if 'SIGN' in name(chr(i),'')}
{'×', '©', '%', '÷', '°', '¶', '+', '¤', '£', '¬', '®', '¢', '<', '±', 'µ', '=', '$', '§', '#', '¥', '>'}

3.8.3 集合操作

比较普遍,可以参考之前的文章

3.9 dict和set的背后

重视一下的几个问题:

  • python里的dict和set的效率有多高?
  • 为什么它们是无序的?
  • 为什么并不是所有的python对象都可以当做dict的键或者set里面的元素?
  • 为什么dict的键和set的顺序是根据它们被添加的次序而定的,以及为什么在映射对象的生命周期中,这个顺序呢并不是一成不变的?
  • 为什么不应该在迭代循环dict或是set的同时往里添加元素?

3.9.1 一个关于效率的实验

最快的是集合,最糟糕的是列表。由于列表的背后没有散列表来支持in运算符,每次搜索都需要扫描一次完整的列表,导致所需的时间线性增长。

3.9.2 字典中的散列表

散列表其实是一个稀疏数组(总是有空白元素的数据称为稀疏数组)。一般认为,散列表中的单元通常叫作表元(bucket)。在dict的散列表当中,每个键值对都占用一个表元,每个表元都有两部分,一个是对键的引用,另一个是对值的引用。因为所有表元的大小一致,所有可以通过偏移量来读取某个表元。
因为python会设法保证大概还有三分之一的表元是空的,所以在快要达到这个阀值的时候,原有的散列值会被复制到一个更大的空间里面。
如果要把一个对象放入散列表,那么首先要计算这个元素键的散列值。python中可以用hash()方法来做这件事情。

1.散列值和相等性

内置的hash()方法可以用于所有的内置类型对象。如果是自定义对象调用hash()的话,实际上运行的是自定义的__hash__.如果两个对象在比较的时候是相等的,那么它们的散列值必须相等,否则就不能正常运行了。

2.散列表算法

获取值:

为了获取my_dict[search_key]背后的值,python首先会调用hash(search_key)来计算search_key的散列值,把这个值最低的几位数字当做偏移量,在散列表里查找表元(具体取几位,得看当前散列值的大小)。若找到的表元是空的,则抛出KeyError异常。若不是空的,则表元里会有found_key:found_value。这时候python会检验search_key == found_key是否为真,如果它们相等的话,就会返回found_value.
如果search_key和found_key不匹配的话,就称为散列冲突。发生这种情况是因为,散列表所做的其实是把随机的元素映射到只有几位的数字上,而散列表本身的索引又只依赖这个数字的一部分。为了解决散列冲入,算法会在散列值中另外取几位,然后用特殊方法处理一下,把新得到的数字再当作索引来寻找表元。这次找到若表元若是空的,则同样会抛出KeyError。若非空,或者键匹配,则返回这个值;或者又发现散列冲突,则重复以上步骤。如下图:
在这里插入图片描述

添加新的元素

在发现空表元的时候会放入一个新的元素

更新现有的键值

在找到相应的表元,原表中的值对象会被替换成新值
另外在插入新值时候,python可能会按照散列表的拥挤程度来决定是否要重新分配内存为它扩容。如果增加了散列表的大小,那散列值所占的位数和用作索引的位数都会随之增加,这样做是为了减少发生散列冲突的概率。

3.9.3 dict的实现及其导致的结果

1.键必须是可散列的

一个散列的对象必须包含下面要求:

  • (1)支持hash()函数,并且通过__hash__()所得到的散列值是不可变的
  • (2)支持通过__eq__()方法来检测相等性
  • (3)若a == b 为真,则hash(a)== hash(b) 也为真
所有用户自定义的对象默认都是可散列的,因为它们的散列值由id()值获取,而且都是不相等的。

如果你实现了一个类的__eq__方法,并且希望它是可散列的,那么它一定要有个恰当的__hash__方法.

2.字典在内存上的开销巨大

因为字典使用了散列表,而散列表又必须是稀疏的,这导致了它在空间上的效率底下。
在用户自定义的类型中,__slot__属性可以改变实例属性的存储方式,由dict变成tuple.
在类中定义__slots__属性的目的是告诉解释器:“这个类中所有实力属性都在这儿了”

class Point():__slots__ = ("x", "y")def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return "X={}-Y={}".format(self.x,self.y)

3.键查询很快

dict是典型的空间换时间:字典类型有着巨大的内存开销,但是它们提供了无视数据大小的快速访问—只要字典被装在内存里。

4.键的次序取决于添加顺序

当往dict里添加新建而又发生散列冲突的时候,新键可能会被安排到另一个位置。

DIAL_CODES本身按照人口排序的,国家人口前10的国家

>>> DIAL_CODES=[
... (86,'China'),
...  (91,'India'),
...  (1,'United States'),
... (62,'Indonesia'),
... (55,'Brazil'),
... (92,'Pakistan'),
...  (880,'Bangladesh'),
...  (234,'Nigeria'),
...  (7,'Russia'),
...  (81,'Japan'),]
>>> d1= dict(DIAL_CODES)
>>> d1.keys()
dict_keys([86, 91, 1, 62, 55, 92, 880, 234, 7, 81])
>>> d2 = dict(sorted(DIAL_CODES))   # 按照国家的电话区号排序
>>> d2.keys()
dict_keys([1, 7, 55, 62, 81, 86, 91, 92, 234, 880])
>>> d3 = dict(sorted(DIAL_CODES, key=lambda x:x[1]))  按照国家英文名拼写排序
>>> d3.keys()
dict_keys([880, 55, 86, 91, 62, 81, 234, 92, 7, 1])
>>> d1 == d2 and d2 == d3
True

5.往字典里添加新键可能会改变已有键的顺序

无论何时往字典里添加新的键,python解释器都可能做出为字典扩容的决定。扩容导致的结果就是新建一个更大的散列表,并把字典里已经有的元素添加到新表里。这个过程可能呢会发生新的散列冲突,导致新散列表中的键的次序变化。要注意的是,上面提到的这些变化是否会发生以及如何发生,都依赖于字典背后的具体实现。
由此可知,不要对字典同时进行迭代和修改。如果想要扫描并修改一个字典,最好分成两步来进行:首先对字典迭代,以得出需要添加的内容,把这些内容放到一个新的字典里,迭代结束以后,再对原有字典进行更新。

3.9.4 set的实现以及导致的结果

set和frozenset的实现也依赖散列表,但在它们的散列表里存放的只有元素的引用(就像在字典中只有存放键而没有响应的值)
特点总结:

  • 结合里的元素必须是散列的
  • 结合很消耗内存
  • 可以很高效的判断元素是否存在与某个集合
  • 元素的次序取决于被添加到集合里的次序
  • 往集合里面添加元素,可能会改变集合里已有元素的次序。

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

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

相关文章

Android下实现GPS定位服务

1.申请Google API Key&#xff0c;参考前面文章 2.实现GPS的功能需要使用模拟器进行经纬度的模拟设置&#xff0c;请参考前一篇文章进行设置 3.创建一个Build Target为Google APIs的项目 4.修改Androidmanifest文件&#xff1a; view plain<uses-library android:name"…

DEDECMS全版本gotopage变量XSS ROOTKIT 0DAY

影响版本&#xff1a; DEDECMS全版本 漏洞描叙&#xff1a; DEDECMS后台登陆模板中的gotopage变量未效验传入数据&#xff0c;导致XSS漏洞。 \dede\templets\login.htm 65行左右 <input type"hidden" name"gotopage" value"<?php if(!empty($g…

Android开源库loopj的android-async-http的 JsonHttpResponseHandler 存在死循环GC_CONCURRENT

我现在用的是 AndroidAsyncHttp 1.4.4 版本&#xff0c;之前遇到一个很奇怪的问题&#xff0c; 当使用 JsonHttpResponseHandler 解析请求的页面出现服务器错误或其他情况返回的内容不是 JSON 字符串时不会调用自己复写实现的 onSuccess 或者 onFailure 方法&#xff0c;将会出…

进程状态转换(了解)

进程三个基本状态&#xff1a;就绪、阻塞、运行 这个比较简单&#xff0c;进程创建后进入就绪状态、然后若CPU空闲或能打断CPU正在执行的进程&#xff08;优先级低的&#xff09;&#xff0c;那么就绪状态转换成运行态&#xff0c;运行时&#xff0c;进程需要用到其他资源&…

2014阿里巴巴校园招聘笔试题 - 中南站

转载于:https://www.cnblogs.com/gotodsp/articles/3530329.html

Spring的IOC原理[通俗解释一下]

1. IoC理论的背景 我们都知道&#xff0c;在采用面向对象方法设计的软件系统中&#xff0c;它的底层实现都是由N个对象组成的&#xff0c;所有的对象通过彼此的合作&#xff0c;最终实现系统的业务逻辑。 图1&#xff1a;软件系统中耦合的对象 如果我们打开机械式手表的后盖&am…

以嵌入式系统设计师考试成绩,开始嵌入式博客之旅

http://www.rkb.gov.cn/jsj/cms/s_contents/download/s_dt201003110106.html 转载于:https://www.cnblogs.com/yueqian-scut/p/3952268.html

SSH框架配置及Maven使用

1.SSH框架配置 1.1. SSH框架介绍 1.2. SSH框架配置 所需资源下载&#xff1a; l jdk; 从Oracle官方网站&#xff1a;http://www.oracle.com/technetwork/cn/java/javase/downloads/index.html下载jdk&#xff0c;win7是默认安装在C:\Program Files (x86)\Java\jdk1.6.0_25路径下…

Flask 从入门到熟悉(不敢称为精通)

文章目录2.1 Flask介绍及其安装2.2 Virtualenv3.1 一个最小的应用3.2 外部课件服务器3.3 调试模式4.1 路由介绍4.2 变量规则4.3 构建URL4.4 HTTP 方法4 总结5.1 静态文件5.2 渲染模板5.3 练习66.1 接收请求数据6.2 请求对象6.3 文件上传6.4 Cookies6 总结77.1 重定向和错误7.2 …

Ext JS 5 beta版发布

原文&#xff1a;Announcing Public Beta of Ext JS 5我们非常高兴的宣布&#xff0c;Sencha Ext JS 5 beta版本开始进行公测了。这个beta版本可以让你、我们Sencha社区来对我们的Ext JS 5的工作进度进行评测。对于所以Ext JS开发人员&#xff0c;这事一个很好的机会来协助完成…

关于癌症的十大谣言

最近&#xff0c;国外网站总结了西方社会中流行的十个关于癌症的谣言&#xff0c;其中很多谣言在我们周围也有广泛的传播。 谣言1&#xff1a;癌症是人为导致的现代疾病 或许在公众的认知里&#xff0c;癌症在今天要比历史上任何时期都重要。不过实际上&#xff0c;癌症可不是一…

[python 进阶] 第7章 函数装饰器和闭包

文章目录7.1 装饰器基础知识7.2 Python何时执行装饰器7.3 使用装饰器改进“策略”7.4 变量作用域(global)备注 -比较字节码&#xff08;暂略&#xff09;7.5 闭包7.6 nonlocal声明global和nonlocal的区别7.7 实现一个简单的装饰器7.8 标准库中的装饰器7.8.1 使用functools.lru_…

自制“低奢内”CSS3登入表单,包含JS验证,请别嫌弃哦。

要求 必备知识 基本了解CSS语法,初步了解CSS3语法知识。和JS/JQuery基本语法。 开发环境 Adobe Dreamweaver CS6 演示地址 演示地址 预览截图(抬抬你的鼠标就可以看到演示地址哦): 制作步骤: 一, html结构 <div id"home"><form id"login" class…

class里面只能写以下5种

转载于:https://www.cnblogs.com/phplearnings/p/3650849.html

【排序】算法(python实现)

文章目录python 排序算法1 插入排序1.1 直接插入排序算法思想1.2 希尔排序算法思想2. 选择排序2.1 简单选择排序2.2 堆排序参考python 排序算法 1 插入排序 1.1 直接插入排序 算法思想 直接插入排序的核心思想就是&#xff1a;将数组中的所有元素依次跟前面已经排好的元素相…

OpenSSL漏洞补救办法详解(转)

CVE-2014-0160漏洞背景 2014年4月7日OpenSSL发布了安全公告&#xff0c;在OpenSSL1.0.1版本中存在严重漏洞(CVE-2014-0160)。OpenSSL Heartbleed模块存在一个BUG&#xff0c;问题存在于ssl/dl_both.c文件中的心跳部分&#xff0c;当攻击者构造一个特殊的数据包&#xff0c;满足…

SharePoint 自定义WebPart之间的连接

1、创建SharePoint解决方案&#xff0c;添加两个WebPart分别用来发送和接收&#xff1b; 2、发送值的WebPart需要继承自IWebPartField(当然&#xff0c;根据需要还可以选择IWebPartField,IWebPartParameters,IWebPartRow,IWebPartTable&#xff0c;具体参见msdn)&#xff0c;原…

C# 基础备忘录

1. decimal 类型调用ToString()方法后没把末尾的0去掉的解决办法: 例子&#xff1a;decimal? money Convert.ToDecimal(10.8950);string moneyStrmoney.Value.ToString(); 结果在同一台机子&#xff0c;两个项目里面会出现两个不同的结果。结果一&#xff1a;moneyStr"1…

PDFlib免费下载地址及详细介绍手册

PDFlib是一个用于创建PDF文档的开发工具,也可直接在你的服务器端产生PDF输出, 可利用PDFLib提供的简单易用的API&#xff08;应用编程接口&#xff09;在服务器或客户端产生PDF文档, PDFlib在生成PDF文档时不需要第3方软件的支持,也不需要其它工具。此产品属于产品 PDFlibPDI 的…

关于VS2010帮助文档的使用和VC6.0在Win7 64位下的使用

由于购置了新的电脑&#xff0c;安装的是Win7 64位的操作系统&#xff0c;这两天我在重新安装编程环境的时候遇到一些问题&#xff0c;现在都解决掉了&#xff0c;分享出来以供需要的人参考。 一、以前使用的是VS2008&#xff0c;从VC6到2008这么多年了一只使用的MSDN是带索引的…