注册公司网站流程,手机网站页面尺寸大小,中企动力科技股份有限公司潍坊分公司,网站开发 实战文章目录3.1 泛映射类型什么是可散列的数据类型#xff08;键的要求#xff09;字典的构造方法3.2 字典推导(dictcomp)3.3 常见的映射方法用setdefault处理找不到的键3.4 映射的弹性键查询3.4.1 defaultdict:处理找不到的键的一个选择注意#xff1a;defaultdict与dict实例化…
文章目录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.UserDict3.6 子类化UserDictMutableMapping.updateMapping.get从dict或者其他内置类继承有什么不好3.7 不可变映射类型动态的只读的映射视图:MappingProxyType3.1 泛映射类型
collections.abc模块有Mapping和MutableMapping 这两个抽象基类它们的作用是为了dict和其他类似的类型定义形式接口然后非抽象映射类型一般不会直接继承这些抽象基类它们会直接对dict或者collections.UserDict进行扩展。这些抽象基类的主要作用是作为形式化的文档它们定义了构建一个映射类型所需要的最基本的接口。然后它们还可以跟isinstance一起被用来判定某个数据是不是广义上的映射类型 from collections import abcmy_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和数值类型)2frozenset3元组只有当元组包含的所有元素都是可散列的情况下。 可以用句话说python里所有的不可变类型都是可散列的 一般来讲用户自定义的类型的对象都是可散列的散列值就是它们的id()函数的返回值。
字典的构造方法 a dict(one1,two2,three3)b{one:1,two:2,three:3}c dict(zip([one,two,three],[1,2,3]))d dict({one:1,two:2,three:3})edict([(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 常见的映射方法
除了
dictdefaultdictOrderedDict
这三种常见方法 在映射对象的方法里setdefault可能是比较微妙的一个。尽管用的次数不多但是它一旦发挥作用就可以节省不少次键查询让程序更高效。
用setdefault处理找不到的键
我们可以使用d.get(k,default)来代替d[k]给找不到的键一个默认的返回值这比处理keyError方便不少) 看个例子: my_dict {子: 鼠, 丑: 牛, 寅: 虎,
... 卯: 兔, 辰: 龙, 巳: 蛇,
... 午: 马, 未: 羊, 申: 猴,
... 酉: 鸡, 戌: 狗, 亥: 猪}my_dict.setdefault(子,属鼠) # 显然键 子存在那么 值 属鼠 也就无用
鼠my_dict.setdefault(行初心,CSDN) # 如果找不到就会添加.
CSDNmy_dict.setdefault(行) # 不存在的键行未指定值默认返回Nonemy_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) 13.4 映射的弹性键查询
为了方便就算某个键在映射里不存在那么你也希望在通过这个键读取值的时候能得到一个默认值。有两个途径帮我们达到这个目的。
1.通过defaultdict这个类型而不是普通的dict2.给自己定义一个dict类型的子类然后在这个子类中实现__missing__方法。
3.4.1 defaultdict:处理找不到的键的一个选择
在用户创建defaultdict对象的时候就需要给它配置一个为找不到的键创造默认值的方法。 具体而言在实例化一个defaultdict的时候需要给构造方法提供一个可调用的对象这个可调用对象会在__getitem__碰到找不到的键的时候被调用让__getitem__返回某种默认值。 比如新建一个字典dddefaultdict(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是个defaultdictK是个找不到的键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 helloc 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 moduleprint(d1[a])
KeyError: adefaultdict的构造
python官方文档中对defaultdict的定义如下:
class collections.defaultdict([default_factory[, ...]])python官方文档中对defaultdict的解释如下:
defaultdi:
dict subclass that calls a factory function to supply missing valuesdefault_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(lastFalse)这样调用它那么它删除并返回第一个被添加进去的元素。 例子 d collections.OrderedDict()d[a] Ad[b] Bd[c] Cfor k ,v in d.items():
... print(k,v)
...
a A
b B
c Cd.popitem(lastFalse)
(a, A)d
OrderedDict([(b, B), (c, C)])collections.ChainMap将多个映射合并为单个映射
该类型可以容纳数个不同的映射对象然后在进行键查找操作的时候这些对象会被当做一个整体逐个查找直到键被找到为止。 例子 import collectionsa {x: 1, z: 3}b {y: 2, z: 4}c collections.ChainMap(a, b)c[x]
1collections.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里剩下的的那些映射类型的方法都是从UserDictMutableMapping和Mapping这些超类继承而来的。特别是最后的Mapping类它虽然是一个抽象类ABC,但是它提供了许多使用的方法。
MutableMapping.update
这个方法不但可以直接利用它还用在__init__里让构造方法可以利用传入的各种参数(其他映射类型元素是(key,value)对的可迭代对象和键值参数)来新建实例。因为这个方法在背后是使用self[key]value来添加新值的所以它其实是在使用我们的__setitem__方法
Mapping.get
从dict或者其他内置类继承有什么不好
3.7 不可变映射类型动态的只读的映射视图:MappingProxyType
标准库里所有的映射类型都是可变的但是有时候你会有这样的需求比如不能让用户错误修改某个映射。
在types模块中引入了一个封装类名叫MappingProxyType。如果给这个类一个映射它会返回一个动态的只读的映射视图。如果对原映射做出了修改这个视图可以观察到但是无法通过这个视图对原映射进行修改。 例子 from types import MappingProxyTyped {1:A}d_proxy MappingProxyType(d)d_proxy
mappingproxy({1: A})d_proxy[1] #d中的内容可以通过d_proxy看到
Ad_proxy[2] x #但是d_proxy不能做任何的修改
Traceback (most recent call last):File stdin, line 1, in module
TypeError: mappingproxy object does not support item assignmentd[2] Bd_proxy #d_proxy是动态的也就是说对d所做的任何改动都会反馈到它上面
mappingproxy({1: A, 2: B})d_proxy[2]
B