《Think Python 2e》学习精粹(十一):字典
1、字典及映射
字典 :包含了一个索引的集合,被称为键(keys) ,和一个值(values )的集合, 一个键对应一个值,这种一一对应的关联被称为键值对(key-value pair) , 有时也被称为项(item) ;
字典与列表类似,但是更加通用,在列表中,索引必须是整数,但在字典中,它们可以是(几乎)任何类型; 在数学语言中,字典表示的是从键到值的 映射,所以也可以说每一个键 “映射到” 一个值; dict函数生成一个不含任何项的新字典(空字典);
>> > eng2sp = dict( )
>> > eng2sp
{ }
花括号 {} 表示一个空字典,你可以使用方括号向字典中增加项;
>> > eng2sp[ 'one' ] = 'uno'
>> > eng2sp
{ 'one' : 'uno' }
输出的格式同样也是输入的格式, 可以像这样创建一个包含三个项的字典:
>> > eng2sp = { 'one' : 'uno' , 'two' : 'dos' , 'three' : 'tres' }
通常来说,字典中项的顺序是不可预知的,但这没有关系,因为字典的元素不使用整数索引来查找,而是用键来查找对应的值;
>> > eng2sp[ 'two' ]
'dos'
>> > eng2sp[ 'four' ]
KeyError: 'four'
len函数也适用于字典,它返回键值对的个数; in 操作符也适用于字典,它可以用来检验字典中是否存在某个键(仅仅有这个值还不够),并返回一个布尔值;
>> > 'one' in eng2sp
True
>> > 'uno' in eng2sp
False
想要知道字典中是否存在某个值,可以使用 values 方法,它返回值的集合,然后你可以使用 in 操作符来验证;
>> > vals = eng2sp.values( )
>> > 'uno' in vals
True
2、字典作为计数器集合
一个字符串,想计算每个字母出现的次数,使用字典的实现有一个优势,即不需要事先知道字符串中有几种字母, 只要在出现新字母时分配存储空间就好了,下面的函数 histogram 叫计数器集合或者直方图:
def histogram ( s) :
d = dict ( )
for c in s:
if c not in d:
d[ c] = 1
else :
d[ c] += 1
return d
字典有一个 get 方法,接受一个键和一个默认值作为参数, 如果字典中存在该键,则返回对应值,否则返回传入的默认值,用这个方法简化的 histogram 函数:
def histogram ( s) :
d = dict ( )
for c in s:
d[ c] = d. get( c, 0 ) + 1
return d
3、循环和字典
def print_hist ( h) :
for c in h:
print ( c, h[ c] )
>> > h = histogram( 'parrot' )
>> > print_hist( h)
a 1
p 1
r 2
t 1
o 1
要以确定的顺序遍历字典,使用内建函数 sorted:
>> > for key in sorted( h) :
.. . print( key, h[ key] )
a 1
o 1
p 1
r 2
t 1
4、逆向查找
字典通过 v(alue) 找 k(ey) ,可能有不止一个的键其映射到值v, 并且没有简单的语法可以完成 逆向查找(reverse lookup) ,必须搜索;
def reverse_lookup ( d, v) :
for k in d:
if d[ k] == v:
return k
raise LookupError( )
raise 语句 能触发异常,这里它触发了 ValueError,这是一个表示查找操作失败的内建异常;逆向查找比正向查找慢得多,频繁执行这个操作或是字典很大,程序性能会变差;
5、字典和列表
def invert_dict ( d) :
inverse = dict ( )
for key in d:
val = d[ key]
if val not in inverse:
inverse[ val] = [ key]
else :
inverse[ val] . append( key)
return inverse
h = { 'p' : 1 , 'a' : 1 , 'r' : 2 , 'o' : 1 , 't' : 1 }
d = invert_dict( h)
print ( d)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new70.py
{ 1: [ 'p' , 'a' , 'o' , 't' ] , 2: [ 'r' ] }
列表可以作为字典中的值,但是不能是键,键必须是 可哈希的(hashable) ;
>> > t = [ 1, 2, 3]
>> > d = dict( )
>> > d[ t] = 'oops'
Traceback ( most recent call last) :
File "<stdin>" , line 1, in ?
TypeError: list objects are unhashable
字典与列表同为可变数据类型,与列表类似,即能作为字典值、但不能为键;
6、备忘录
备忘录(memo) :存储之前计算过的值以便今后使用的记录,字典便可以用作为备忘录;
known = { 0 : 0 , 1 : 1 }
def fibonacci ( n) :
if n in known:
return known[ n]
return fibonacci( n- 1 ) + fibonacci( n- 2 )
7、全局变量
__ main__ 中的变量可以被任何函数访问,它们也被称作 全局变量(global) ;
与函数结束时就会消失的局部变量不同,不同函数调用时全局变量一直都存在; 全局变量普遍用作 标记(flag) , 也就是说明(标记)一个条件是否为真的布尔变量; 要在函数内对全局变量重新赋值,必须在使用之前 声明(declare) 该全局变量;
been_called = False
def example2 ( ) :
global been_called
been_called = True
example2( )
print ( been_called)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new82.py
True
global 语句 告诉编译器变量是全局变量、不生成新的变量;不可变类型全局变量在函数中引用前必须声明,可变类型(例如列表、字典)全局变量在函数中可以不加声明引用并修改、但不能重新赋值; 全局变量有时是很有用的,但如果程序中有很多全局变量,而且修改频繁, 这样会增加程序调试的难度;
8、调试
针对调试大数据集的一些建议:
如果可能,减小数据集合的大小; 检查摘要和类型; 编写自检代码; 格式化输出; 搭建脚手架。