python进阶(第三章1) 字典

文章目录

    • 3.1 泛映射类型
        • 什么是可散列的数据类型(键的要求)
        • 字典的构造方法
    • 3.2 字典推导(dictcomp)
    • 3.3 常见的映射方法
        • 用setdefault处理找不到的键
    • 3.4 映射的弹性键查询
      • 3.4.1 defaultdict:处理找不到的键的一个选择
        • 注意:
        • defaultdict与dict实例化字典类型的区别
        • defaultdict的构造
      • 3.4.2 特殊方法__missing__
    • 3.5 字典的变种
        • collections.OrderedDict (添加键会保持顺序)
        • collections.ChainMap(将多个映射合并为单个映射)
        • collections.Counter
          • 例子:统计单词中各个字母出现的次数
        • collections.UserDict
    • 3.6 子类化UserDict
      • MutableMapping.update
      • Mapping.get
        • 从dict或者其他内置类继承有什么不好?
    • 3.7 不可变映射类型(动态的只读的映射视图:MappingProxyType)

3.1 泛映射类型

collections.abc模块有Mapping和MutableMapping 这两个抽象基类,它们的作用是为了dict和其他类似的类型定义形式接口,然后非抽象映射类型一般不会直接继承这些抽象基类,它们会直接对dict或者collections.UserDict进行扩展。这些抽象基类的主要作用是作为形式化的文档,它们定义了构建一个映射类型所需要的最基本的接口。然后它们还可以跟isinstance一起被用来判定某个数据是不是广义上的映射类型:

>>> from collections import abc
>>> my_dict={}                    # 字典是典型的键值对
>>> isinstance(my_dict,abc.Mapping)
True                                
>>> isinstance([1, 2], abc.Mapping)
False									#列表时序列
>>> isinstance((1, 2), abc.Mapping)
False								#元组也是序列
>>> isinstance('sdbd', abc.Mapping)
False								#字符串也是序列
  • 这里用isintance而不是type来检查某个参数是否为dict类型,因为这个参数有可能不是dict,而是一个比较另类的映射类型。(这句话不太明白)
  • 标准库里的所有映射类型都是利用dict来实现的,因此它们有个共同的限制,即只有可散列的数据类型才可以用作这些映射里的键(只有键有这个要求,值没有此要求)

什么是可散列的数据类型(键的要求)

如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的而且这个对象需要实现__hash__()方法。另外可散列对象还要有__eq__()方法,这样才能和其他键作比较。如果两个散列对象是相等的,那么它们的散列值一定是一样
的。

可散列类型包括:

  • (1)原子不可变类型(str, bytes和数值类型)
  • (2)frozenset
  • (3)元组:只有当元组包含的所有元素都是可散列的情况下。
    可以用句话说:python里所有的不可变类型都是可散列的
    一般来讲用户自定义的类型的对象都是可散列的,散列值就是它们的id()函数的返回值。

字典的构造方法

>>> a= dict(one=1,two=2,three=3)
>>> b={'one':1,'two':2,'three':3}
>>> c= dict(zip(['one','two','three'],[1,2,3]))
>>> d = dict({'one':1,'two':2,'three':3})
>>> e=dict([('two',2),('one',1),('three',3)])
>>> a == b ==c == d == e
True
  • 注意这里的相等,只不过是值相等,但是不同的对象

3.2 字典推导(dictcomp)

列表生成器和生成器表达式的概念已经移植到了字典上,从而有了字典推导。
字典推导可以从任何键值对作为元素的可迭代对象中构建出字典。
例子:

>>> DIAL_CODES=[
... (86,'China'),
... (91,'India'),
... (1,'United States'),
... (62,'Indonesia'),
... (55,'Brazil'),
... (92,'Pakistan'),
... (880,'Bangladesh'),
... (234,'Nigeria'),
... (7,'Russia'),
... (81,'Japan'),
... ]
>>> country_code={country:code for code,country in DIAL_CODES}
>>> country_code
{'China': 86, 'India': 91, 'United States': 1, 'Indonesia': 62, 'Brazil': 55, 'Pakistan': 92, 'Bangladesh': 880, 'Nigeria': 234, 'Russia': 7, 'Japan': 81}
>>> {code:country.upper() for country,code in country_code.items() if code <66}
{1: 'UNITED STATES', 62: 'INDONESIA', 55: 'BRAZIL', 7: 'RUSSIA'}

字典推导的表达式会蔓延到其他数据结构类型

3.3 常见的映射方法

除了

  • dict
  • defaultdict
  • OrderedDict

这三种常见方法
在映射对象的方法里,setdefault可能是比较微妙的一个。尽管用的次数不多,但是它一旦发挥作用,就可以节省不少次键查询,让程序更高效。

用setdefault处理找不到的键

我们可以使用d.get(k,default)来代替d[k],给找不到的键一个默认的返回值(这比处理keyError方便不少)
看个例子:

>>> my_dict = {'子': '鼠', '丑': '牛', '寅': '虎',
...                '卯': '兔', '辰': '龙', '巳': '蛇',
...                '午': '马', '未': '羊', '申': '猴',
...                '酉': '鸡', '戌': '狗', '亥': '猪'}
>>> my_dict.setdefault('子','属鼠')       # 显然键 '子'存在,那么 值 '属鼠' 也就无用
'鼠'
>>> my_dict.setdefault('行初心','CSDN')      # 如果找不到,就会添加.
'CSDN'
>>> my_dict.setdefault('行')    # 不存在的键"行",未指定值,默认返回None
>>> my_dict
{'子': '鼠', '丑': '牛', '寅': '虎', '卯': '兔', '辰': '龙', '巳': '蛇', '午': '马', '未': '羊', '申': '猴', '酉': '鸡', '戌': '狗', '亥': '猪', '行初心': 'CSDN', '行': None}

例子2:(使用dict.setdefault()方法来设置默认值,统计字符串出现的次数)

strings = ('puppy', 'kitten', 'puppy', 'puppy','weasel', 'puppy', 'kitten', 'puppy')
counts = {}
for kw in strings:counts.setdefault(kw, 0)counts[kw] += 1 

dict.setdefault()方法的返回值可以重写for循环中的代码,使其更加简洁:

strings = ('puppy', 'kitten', 'puppy', 'puppy','weasel', 'puppy', 'kitten', 'puppy')
counts = {}
for kw in strings:counts[kw] = counts.setdefault(kw, 0) + 1

3.4 映射的弹性键查询

为了方便,就算某个键在映射里不存在,那么你也希望在通过这个键读取值的时候能得到一个默认值。有两个途径帮我们达到这个目的。

  • (1).通过defaultdict这个类型而不是普通的dict
  • (2).给自己定义一个dict类型的子类,然后在这个子类中实现__missing__方法。

3.4.1 defaultdict:处理找不到的键的一个选择

在用户创建defaultdict对象的时候,就需要给它配置一个为找不到的键创造默认值的方法。
具体而言,在实例化一个defaultdict的时候,需要给构造方法提供一个可调用的对象,这个可调用对象会在__getitem__碰到找不到的键的时候被调用,让__getitem__返回某种默认值。
比如,新建一个字典:dd=defaultdict(list),如果键’new-key’在dd中不存在的话,表达式dd[‘new-key’]会按照以下步骤行事。

  • (1).调用list()来创建新列表
  • (2).把这个新列表作为值,'new-key’作为它的键,放到dd中。
  • (3).返回这个列表的引用
    而这个用来生成默认值的可调用对象存放在名为default_factory的实例属性里。
    如果在创建defaultdict的时候没有指定default_factory,查询不存在的键会触发KeyError.

注意:

  • defaultdict里面的default_factory只会在__getitem__里被调用,在其他的方法里完全不会发挥作用。比如,dd是个defaultdict,K是个找不到的键,dd[k]这个表达式会调用default_factory创造某个默认值,而dd.get(k)则会返回None.

所有 这一切背后的功臣其实是特殊方法__missing__.它会在defaultdict遇到找不到的键的时候调用default_factory,而实际上这个特性是所有映射类型都可以去选择的。

看个例子:

from collections import defaultdict
class from_defaultdict(defaultdict):def __getitem__(self, key):return 'hello'c = from_defaultdict(list)print(c['new-key'])	

结果如下:
在这里插入图片描述

defaultdict与dict实例化字典类型的区别

使用defaultdict任何未定义的key都会默认返回一个根据method_factory参数不同的默认值, 而相同情况下dict()会返回KeyError.
比较下面代码:

from collections import defaultdict
d1 = dict()
d2 = defaultdict(list)
print(d2['a'])
print(d1['a'])

输出:

[]
Traceback (most recent call last):File "/home/maxzhang/PycharmProjects/pythoncode/t.py", line 5, in <module>print(d1['a'])
KeyError: 'a'

defaultdict的构造

python官方文档中对defaultdict的定义如下:

class collections.defaultdict([default_factory[, ...]])

python官方文档中对defaultdict的解释如下:

defaultdi:
dict subclass that calls a factory function to supply missing values
  • default_factory 接收一个工厂函数作为参数, 例如int str,list,set等.
  • defaultdict在dict的基础上添加了一个__missing__(key)方法, 在调用一个不存的key的时候, defaultdict会调用__missing__, 返回一个根据default_factory参数的默认值, 所以不会返回Keyerror.

3.4.2 特殊方法__missing__

所有的映射类型在处理找不到的键的时候,都会牵扯到__missing__方法。这也是和这个方法称作’missing’的原因。虽然基类dict并没有定义这个方法,但是dict是知道有这么一个东西存在的。也就是说,如果有一个类继承了dict,然后这个继承类提供了__missing__方法,那么在__getitem__碰到找不到的键的时候,python会自动调用它。而不是抛出异常。

  • 注意:__missing__方法只会被__getitem__调用。提供__missing__方法对get或者__contains__这些方法的使用没有影响。

如果要自定义一个映射类型,更合适的策略是继承collections.UserDict类。

3.5 字典的变种

collections.OrderedDict (添加键会保持顺序)

这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的。OrderedDict的popitem方法默认删除并返回的是字典里的最后一个元素,但是如果像my_odict.popitem(last=False)这样调用它,那么它删除并返回第一个被添加进去的元素。
例子:

>>> d = collections.OrderedDict()
>>> d['a'] = 'A'
>>> d['b'] = 'B'
>>> d['c'] = 'C'
>>> for k ,v in d.items():
...     print(k,v)
... 
a A
b B
c C
>>> d.popitem(last=False)
('a', 'A')
>>> d
OrderedDict([('b', 'B'), ('c', 'C')])

collections.ChainMap(将多个映射合并为单个映射)

该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当做一个整体逐个查找,直到键被找到为止。
例子:

>>> import collections
>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> c = collections.ChainMap(a, b)
>>> c['x']
1

collections.Counter

这个映射会给键准备一个整数计数器。每次更新一个键的时候都会增加这个基数器。所以这个类型可以用来给可散列表对象计数,或者是当成多重集来使用—多重集合就是集合里的元素可以出现不止一次。Counter实现了+和-运算符用来合并记录,还有像most_common([n])这类很有用的方法。most_common([n])会按照次序返回映射里最常见的n个键和它们的计数。

例子:统计单词中各个字母出现的次数
>>> ct = collections.Counter('afalfjlahgksdadaa')
>>> ct
Counter({'a': 6, 'f': 2, 'l': 2, 'd': 2, 'j': 1, 'h': 1, 'g': 1, 'k': 1, 's': 1})
>>> ct.update('aaaaaaaaadffdwe')
>>> ct
Counter({'a': 15, 'f': 4, 'd': 4, 'l': 2, 'j': 1, 'h': 1, 'g': 1, 'k': 1, 's': 1, 'w': 1, 'e': 1})
>>> ct.most_common(2)
[('a', 15), ('f', 4)]

collections.UserDict

这个类其实就是把标准dict用纯python又实现了一遍
UserDict就是让用户继承写子类的。

3.6 子类化UserDict

就创造自定义映射类型来说,以UserDict为基类,总比以普通的dict为基类要来的方便。
更倾向于从UserDict而不是从dict继承的主要原因是,后者有时会在某些方法的实现上走一些捷径,导致我们不得不在它的子类中重写这些方法,但是UserDict就不会带来这些问题。
另外一个值得注意的地方是,UserDict并不是dict的子类,但是UserDict有一个叫做data的属性是dict的实例,这个属性就是UserDict最终存储数据的地方。
例子:

import collectionsclass StrKeyDict(collections.UserDict):def __missing__(self, key):if isinstance(key,str):raise KeyErrorreturn self[str(key)]def __contains__(self, key):return str(key) in self.datadef __setitem__(self, key, item):self.data[str(key)] = item

因为UserDict 继承的是MutableMapping,所以StrKeyDict里剩下的的那些映射类型的方法都是从UserDict,MutableMapping和Mapping这些超类继承而来的。特别是最后的Mapping类,它虽然是一个抽象类(ABC),但是它提供了许多使用的方法。

MutableMapping.update

这个方法不但可以直接利用,它还用在__init__里,让构造方法可以利用传入的各种参数(其他映射类型,元素是(key,value)对的可迭代对象和键值参数)来新建实例。因为这个方法在背后是使用self[key]=value来添加新值的,所以它其实是在使用我们的__setitem__方法

Mapping.get

从dict或者其他内置类继承有什么不好?

3.7 不可变映射类型(动态的只读的映射视图:MappingProxyType)

标准库里所有的映射类型都是可变的,但是有时候你会有这样的需求,比如不能让用户错误修改某个映射。

在types模块中引入了一个封装类名叫MappingProxyType。如果给这个类一个映射,它会返回一个动态的只读的映射视图。如果对原映射做出了修改,这个视图可以观察到,但是无法通过这个视图对原映射进行修改。
例子:

>>> from types import MappingProxyType
>>> d = {1:'A'}
>>> d_proxy = MappingProxyType(d)
>>> d_proxy
mappingproxy({1: 'A'})
>>> d_proxy[1]                  #d中的内容可以通过d_proxy看到
'A'
>>> d_proxy[2] = 'x'          #但是d_proxy不能做任何的修改
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'mappingproxy' object does not support item assignment
>>> d[2]= 'B'
>>> d_proxy                 #d_proxy是动态的,也就是说对d所做的任何改动都会反馈到它上面
mappingproxy({1: 'A', 2: 'B'})
>>> d_proxy[2]
'B'
>>> 

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

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

相关文章

python基础 list和tuple

文章目录一、list1、len()函数可以获得list元素的个数2、索引从0开始3、末尾追加 append(xx)4、也可以把元素插入到指定的位置&#xff0c;比如索引号为1的位置(insert)5、末尾删除pop() &#xff0c;并且返回该值6、要删除指定位置的元素&#xff0c;用pop(i)方法&#xff0c;…

python基础 dict和set

文章目录dictset4.用集合为列表去重5.集合的增 add,update6.集合的删 discard,remove,pop,clear7 集合运算7.1 子集(<或者issubset()方法)7.2并集(|或者union()方法)7.3 交集(&或者intersection())7.4 差集(-或者difference()方法)7.5 对称集(^或者symmetric_difference…

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

文章目录3.8 集合论nee中的元素在haystack中出现的次数&#xff0c;可以在任何可迭代对象上3.8.1集合字面量3.8.2 集合推导3.8.3 集合操作3.9 dict和set的背后3.9.1 一个关于效率的实验3.9.2 字典中的散列表1.散列值和相等性2.散列表算法获取值&#xff1a;添加新的元素更新现有…

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;原…