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

HDU 2818 Building Block

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid2818 题意:给定N个blocks&#xff0c;分在N个堆里&#xff0c;然后又P个操作&#xff0c;每次将x所在的堆放在y所在的堆上&#xff0c;或者询问x的下面有几个blocks 做法&#xff1a;带权并查集 因为要查询x的下面有多少bl…

百度社会化分享组件使用问题

今天下午玩了玩百度的社会化分享sdk,我是在这下载的sdk http://developer.baidu.com/frontia/sdk 谁知道这个下载链接是没更新的,还是1.0版本的,是尼玛13年初的版本 捣鼓了半天各种bug 然后去百度官网重新找http://developer.baidu.com/wiki/index.php?titledocs/frontia/res…

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"…

python 链表 【测试题】

文章目录注意&#xff1a;实例讲解1 .链表基本功能2. 根据值删除链表中的节点信息答案&#xff1a;3.反转一个单链表信息答案4.合并两个有序链表信息答案5.删除排序链表中的重复元素信息答案6.移除链表元素信息7.环形链表信息进阶思路答案注意&#xff1a; 这里的head是只存储…

WebService应用一例,带有安全验证

1、创建WEB项目&#xff0c;添加WEB服务WebService1.asmx&#xff0c;代码如下&#xff1a; 1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Web;5 using System.Web.Services;6 7 namespace WebService8 {9 /// <summary> …

linux集成开发环境

Linux操作系统的种种集成开发环境随着Linux的逐渐兴起&#xff0c;已经有为数众多的程序在上面驰骋了&#xff0c;许多开发环境(Development Environment)也应运而生。好的开发环境一定是集成了编辑、编译和调试等多项功能并且易于使用。本文介绍了一些在Linux上流行的开发环境…

mysql技术内幕《读书笔记》

文章目录1. mysql 体系结构和存储引擎1.5 连接mysql1.5.11. mysql 体系结构和存储引擎 1.5 连接mysql 连接mysql操作是一个连接进程和mysql数据库实例进行通信。 本质是进程通信&#xff0c;常用的进程通信方式有管道&#xff0c;命名管道&#xff0c;命名字&#xff0c;TCP/…

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;将会出…

python【进阶】4.文本和字节序列

文章目录1. 字符、码位和字节表述4.1字符问题2. bytes、bytearray 和 memoryview 等二进制序列的独特特性3. 全部 Unicode 和陈旧字符集的编解码器4.避免和处理编码错误5.处理文本文件的最佳实践6.默认编码的陷阱和标准 I/O 的问题7.规范化 Unicode 文本,进行安全的比较8.规范化…

C#序列化和反序列化

序列化和反序列化我们可能经常会听到&#xff0c;其实通俗一点的解释&#xff0c;序列化就是把一个对象保存到一个文件或数据库字段中去&#xff0c;反序列化就是在适当的时候把这个文件再转化成原来的对象使用。我想最主要的作用有&#xff1a; 1、在进程下次启动时读取上次保…

python【进阶】5.一等函数(注销)

在 Python 中,函数是一等对象。编程语言理论家把“一等对象”定义为满足下述条件的程 序实体: 在运行时创建能赋值给变量或数据结构中的元素能作为参数传给函数能作为函数的返回结果 在 Python 中,所有函数都是一等对象。 5.1 把函数视作对象 >>> def d(n): ... …

进程状态转换(了解)

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

rebuild online意外终止导致ora-8104错误的实验

rebuild online意外终止导致ora-8104错误的实验 SQL> !oerr ora 810408104, 00000, "this index object %s is being online built or rebuilt"// *Cause: the index is being created or rebuild or waited for recovering // from the online (re)build // *Act…

关于range方法,如果你觉得python很简单就错了

前言&#xff1a;在系统学习迭代器之前&#xff0c;我一直以为 range() 方法也是用于生成迭代器的&#xff0c;现在却突然发现&#xff0c;它生成的只是可迭代对象&#xff0c;而并不是迭代器&#xff01; 1、range() 是什么&#xff1f; 对于 range() 函数&#xff0c;有几个注…

centos下crontab的使用

1.作用使用crontab命令可以修改crontab配置文件&#xff0c;然后该配置由cron公用程序在适当的时间执行&#xff0c;该命令使用权限是所有用户。2.格式crontab [-u user] {-l | -r | -e}3.crontab命令选项: -u指定一个用户, -l列出某个用户的任务计划, -r删除某个用户的任务, -…

关于python3中的包operator(支持函数式编程的包)

文章目录1.functools2.operator.itemgetter3.operator.attrgetter虽然 Guido 明确表明,Python 的目标不是变成函数式编程语言,但是得益于 operator 和 functools 等包的支持,函数式编程风格也可以信手拈来。接下来的两节分别介绍这两 个包。 1.functools 示例1 使用 reduce 函…