【读书笔记】《流畅的python》3.5-3.7 读书笔记

一、字典的变种(3.5)

这一节总结了标准库里 collections 模块中,除了 defaultdict 之外的不同映射类 型。
collections.OrderedDict
这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致 的。OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素,但是如果像 my_odict.popitem(last=False) 这样调用它,那么它删除并返回第一个被添加进 去的元素。
collections.ChainMap 该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被 当作一个整体被逐个查找,直到键被找到为止。这个功能在给有嵌套作用域的语言做解释 器的时候很有用,可以用一个映射对象来代表一个作用域的上下文。
Python 变量查询规则的代码片段:

import builtins 
pylookup = ChainMap(locals(), globals(), vars(builtins))

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

ct = collections.Counter('abracadabra')
print(ct)

输出:
Counter({‘a’: 5, ‘b’: 2, ‘r’: 2, ‘c’: 1, ‘d’: 1})

 ct = collections.Counter('abracadabra')
 ct.update('aaaaazzz')
 print(ct)

输出:
Counter({‘a’: 10, ‘z’: 3, ‘b’: 2, ‘r’: 2, ‘c’: 1, ‘d’: 1})

ct = collections.Counter('abracadabra')
ct.update('aaaaazzz')
print(ct.most_common(2))

输出:
[(‘a’, 10), (‘z’, 3)]

colllections.UserDict
这个类其实就是把标准 dict 用纯 Python 又实现了一遍。
跟 OrderedDict、ChainMap 和 Counter 这些开箱即用的类型不同,UserDict 是让用户 继承写子类的。

二、子类化UserDict(3.6)

就创造自定义映射类型来说,以 UserDict 为基类,总比以普通的 dict 为基类要来得方 便。
更倾向于从 UserDict 而不是从 dict 继承的主要原因是,后者有时会在某些方法的实 现上走一些捷径,导致我们不得不在它的子类中重写这些方法,但是 UserDict 就不会带 来这些问题。

一个值得注意的地方是,UserDict 并不是 dict 的子类,但是 UserDict 有一个叫 作 data 的属性,是 dict 的实例,这个属性实际上是 UserDict 最终存储数据的地方。 这样做的好处是,UserDict 的子类就能在实现 setitem 的时候避免 不必要的递归,也可以让 contains 里的代码更简洁。

无论是添加、更新还是查询操作,StrKeyDict 都会把非字符串的键转换 为字符串

import collections 
class StrKeyDict(collections.UserDict):   # StrKeyDict 是对 UserDict 的扩展。
	def __missing__(self, key): 
		if isinstance(key, str): 
			raise KeyError(key) 
		return self[str(key)] 
		
	def __contains__(self, key): 
		return str(key) in self.data   #  __contains__ 则更简洁些。这里可以放心假设所有已经存储的键都是字符串。因 此,只要在 self.data 上查询就好了,并不需要像 StrKeyDict0 那样去麻烦self.keys()。
		
	def __setitem__(self, key, item): 
		self.data[str(key)] = item   # __setitem__ 会把所有的键都转换成字符串。由于把具体的实现委托给了 self.data 属性,这个方法写起来也不难。
	

因为 UserDict 继承的是 MutableMapping,所以 StrKeyDict 里剩下的那些映射类型的 方法都是从 UserDict、MutableMapping 和 Mapping 这些超类继承而来的。特别是最后 的 Mapping 类,它虽然是一个抽象基类(ABC),但它却提供了好几个实用的方法。以 下两个方法值得关注:
MutableMapping.update 这个方法不但可以为我们所直接利用,它还用在 init 里,让构造方法可以利用 传入的各种参数(其他映射类型、元素是 (key, value) 对的可迭代对象和键值参数) 来新建实例。因为这个方法在背后是用 self[key] = value 来添加新值的,所以它其实 是在使用我们的 setitem 方法。
Mapping.get 这个方法的实现方式跟 StrKeyDict0.get 是一模一样的。

比起 StrKeyDict,TransformDict 的通用性更强,也更复 杂,因为它把键存成字符串的同时,还要按照它原来的样子存一份。

三、 不可变映射类型(3.7)

标准库里所有的映射类型都是可变的,但有时候你会有这样的需求,比如不能让用户错误 地修改某个映射。
从 Python 3.3 开始,types 模块中引入了一个封装类名叫 MappingProxyType。如果给这 个类一个映射,它会返回一个只读的映射视图。虽然是个只读视图,但是它是动态的。这 意味着如果对原映射做出了改动,我们通过这个视图可以观察到,但是无法通过这个视图 对原映射做出修改。

用 MappingProxyType 来获取字典的只读实例 mappingproxy:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值