流畅的python--第三章
字典
示例3-1-1字典推导式
示例3-1-2映射拆包
在调用函数时,不止一个参数可以使用**
。但是所有键都要是字符串,而且在所有参数中,是唯一的(因为关键字参数不可重复)。
示例3-1-3使用|
合并映射
合并映射遵循重复键情况下后键覆盖前键的规律。
可哈希
如果一个对象的哈希码在整个生命周期内永不改变(依托__hash__()
方法),而且可与其他对象比较(依托__eq__
方法),那么这个对象就是可哈希的。
数值类型以及不可变的扁平类型str
和bytes
均是可哈希的。如果容器类型是不可变的,而且所含的对象全是可哈希的,那么容器类型自身也是可哈希的。 frozenset
对象全部是可哈希的,因为按照定义,,每一个元素都必须是可哈希的。
仅当所有项均可哈希,tuple
对象才是可哈希的。
一个对象的哈希码根据所用的
Python
版本和设备架构有所不同,如果出于安全考量而在哈希计算过程汇总加盐,那么哈希码也会发生变化。
插入或更新可变的值
根据python
快速失败的原则,当键k
不存在时,d[k]
抛出错误。深谙python
的人知道,如果觉得默认值比抛出KeyError
更好,则可以使用d.get(k, default)
。
在目标目录编写脚本index0.py
,即下面脚本。下载zen.txt
放在目标目录。
执行脚本:python index0.py zen.txt
import re
import sys
WORD_RE = re.compile(r'\w+')
index = {}
with open(sys.argv[1], encoding='utf-8') as fp:
for line_no, line in enumerate(fp, 1):
for match in WORD_RE.finditer(line):
word = match.group()
column_no = match.start() + 1
location = (line_no, column_no)
occurences = index.get(word, []) # 获取word出现的位置列表,如未找到,则返回[] ---1
occurences.append(location) # 把新找到的位置追加到occurrences ---2
index[word] = occurences # 把更新后的occurrences放入index字典 ---3
for word in sorted(index, key=str.upper): # sorted函数的key参数不是调用str.upper方法,而是传入那个方法的引用,供sorted函数排序各个词,规范化输出。
print(word, index[word])
结果显示:
注释1,2,3三行代码可以用一行替换
index.setdefault(word, []).append(location)
,获取word
出现的位置列表,如未找到,则设为[]
,setdefault
返回该列表,可以直接更新,不用再搜索一次。
自动处理缺失的键
针对字典的键可能不存在,为了防止出现错误,会人为设置:第一种把普通的dict
换为defaultdict
;第二种是定义dict
或其他映射类型的子类,实现__missing__
方法。
import re
import sys
WORD_RE = re.compile(r'\w+')
index = collections.defaultdict(list) # 创建一个defaultdict对象,把default_factory设为list构造函数
with open(sys.argv[1], encoding='utf-8') as fp:
for line_no, line in enumerate(fp, 1):
for match in WORD_RE.finditer(line):
word = match.group()
column_no = match.start() + 1
location = (line_no, column_no)
index[word].append(location) # 如果index中没有word键,则调用default_factory生成缺失的值。这里生成一个空列表,赋值给index[word
],然后返回空列表
# 按字母表顺序显示
for word in sorted(index, key=str.upper):
print(word, index[word])
__missing__
方法
dict
的变体
内置的dict
也可以保留键的顺序。使用OrderedDict
最主要原因是编写与早期Python
版本兼容的代码。不过dict
和OrderedDict
之间还有一些差异。
OrderedDict
的等值检查考虑顺序OrderedDict
的popitem()
方法签名不同,可通过一个可选参数指定移除哪一项。OrderedDict
多了一个move_to_end()
方法,便于把元素的位置移到某一端。- 常规的
dict
主要用于执行映射操作,插入顺序是次要的 OrderedDict
的目的是方便执行重新排序操作,空间利用率、迭代速度和更新操作的性能是次要的。- 从算法上看,
OrderedDict
处理频繁重新排序操作的效果比dict
好,因此适合用于跟踪近期存取情况(例如在LRU
缓存中)
collections.ChainMap
ChainMap实例存放一组映射,可作为一个整体来搜索。查找操作按照输入映射在构造函数调用中出现的顺序执行,一旦在某个映射中找到指定的键,旋即结束。
ChainMap实例不复制输入映射,而是存放映射的引用。ChainMap的更新或插入操作只影响第一个输入映射。
collections.Counter
这是一种对键计数的映射。更新现有的键,计数随之增加。可用于统计
可哈希对象的实例数量.
不可变映射
标准库提供的映射类型都是可变的,不过有时也需要防止用户意外更改映射。types
模块提供的MappingProxyType
是一个包装类,把传入的映射包装成一个mappingproxy
实例,这是原映射的动态代理,只可读取。
这意味着,对原映射的更新将体现在mappingproxy
实例身上,但是不能通过mappingproxy
实例更改映射。
MappingProxyType
根据dict
对象构建只读的mappingproxy
实例。
字典视图
dict的实例方法.keys()、.values()、和.items()分别返回dict_keys、dict_values和dict_items类的实例。这些字典视图是dict内部实现使用的数据结构的只读投影。
所有字典视图均支持的一些基本操作。
视图对象是动态代理。更新原dict对象后,现有视图立即就能看到变化。
集合论
集合是一组唯一的对象。集合的基本作用是去除重复项。
如果想去除重复项,同时保留每一项首次出现位置的顺序,那么现在使用dict
即可.
集合元素必须是可哈希对象。set
类型不可哈希,因此不能构建嵌套set
实例的set
对象。但是frozenset
可以哈希,所以set
对象可以包含frozenset
元素。
除了强制唯一性之外,集合类型通过中缀运算符实现了许多集合运算。给定两个集合a
和b
,a|b
计算并集,a&b
计算交集,a-b
计算差集,a^b
计算对称差集。
set
字面量
set
字面量的句法与集合的数学表示法几乎一样,例如{1}
、{1,2}
等。唯一一点例外:空set
没有字面量表示法,必须写作set()
。
frozenset
没有字面量句法,必须调用构造函数创建。
集合推导式
构建一个集合,元素为Unicode
名称中带有“SIGN”一词的Latin-1
字符。
使用&运算符可以请以获取两个字典都有的键。
注意:
&
运算符和|
运算符均返回一个set