第四章 字典
1 略去
2 创建和使用字典
- 字典,通过 名字 引用 值 的一种数据结构,这种数据结构成为 映射(mapping),其中key唯一,而 值 不一定;
- 值 没有特定顺序,但都存储在一个特定的 键(key)中,键可以是数字、字符串、元组;
- 键—值 序列对称为 项;
- 字典构成:a_dict = {key_1:value_1, key_2, value_2,……},可以通过key来引用value,反之则不可以;
#实现电话号码索引
>>> name = ['Tom', 'Lily', 'John', 'Jenny']
>>> phone = ['0123', '1234', '2345', '3456']
#查找John的电话号码
>>> phone[name.index('John')]
'2345'
#注意电话号码不要用 数字 表示,因为八进制数字都是以0开头的
2.1 dict函数
通过其他映射(如字典)或(键,值)序列对来创建字典
# 方法1
>>> items = [('John', '0123'), ('Tom', '1234'), ('Matt', '2345')]
>>> a_dict = dict(items)
>>> a_dict
{'Matt': '2345', 'John': '0123', 'Tom': '1234'}
# 方法2
>>> d = dict(name = 'John', age = '42')
>>> d
{'age': '42', 'name': 'John'}
# 方法3
>>> dict = {'John':'0123', 'Tom':'1234', 'Matt':'2345'}
>>> dict
{'Matt': '2345', 'John': '0123', 'Tom': '1234'}
# dict[key_name]→调用对应的value
>>> dict['John']
'0123'
2.2 基本字典操作
>> d = {'John':'0123', 'Tom':'1234', 'Matt':'2345'}
>>> len(d) #返回d中 项 的个数
3
>>> d['Tom'] = '4321' #将 value 赋给 key
>>> d['Tom'] #调用 key 对应的 value
'4321'
>>> del d['Tom'] #删除 项
>>> d['Rober'] = '3456' #添加 项
>>> d
{'Matt': '2345', 'John': '0123', 'Rober': '3456'}
>>> 'Tom' in d #成员资格
False
字典与列表的重要区别:
- 键类型:key不一定是整型数据,也可能是其他不可变类型,如浮点型(实型)、字符串或元组;
>>> a_list = []
>>> a_list[3] = 'John'
IndexError: list assignment index out of range
>>> b_list = 5*[None] #建立含有5个空元素的列表
>>> b_list[3] = 'John'
>>> b_list
[None, None, None, 'John', None]
>>> a_dict = {}
>>> a_dict[3] = 'John' #此处的 3 是key,不是编号
>>> a_dict['name'] = 'Tom'
>>> a_dict
{3: 'John', 'name': 'Tom'}
- 自动添加:可以通过为 key 指定 value 来添加新项,值 也不能关联到列表之外的索引上;
- 成员资格:检查的是 key 而不是 value,list 中 value in list 查找的是 value;
- 字典中检查 key 的成员资格的效率要比 list 高效;
【例子】代码清单4-1 电话簿
#一个用于查找people电话号码和地址的程序
#创建用户信息库
user_info = {
'John':{'phone':'0123','addr':'J'},
'Tom':{'phone':'1234','addr':'T'},
'Lily':{'phone':'2345','addr:'L'},
'Matt':{'phone':'3456','addr':'M'},
'Robert':{'phone':'4567','addr':'R'}
}
label = {
'phone':'phone number',
'addr':'address'
}
#上述两个字典公用的 key 相同
#获取用户需求
name = raw_input('Name: ')
choice = raw_input('The info you needed, phone number(P) or address(A): ')
if choice == 'P': key = 'phone'
if choice == 'A': key = 'addr'
print "%s's %s is %s." % (name, label[key], user_info[name][key])
#注意最后的user_info[name][key],是先查找到了user_info 中的 name,然后又查找到了 name 中的 key 对应的 值。
-----------------------------------------------------
运行结果:
Name: Matt
The info you needed, phone number(P) or address(A): P
Matt's phone number is 3456.
-----------------------------------------------------
2.3 字典的格式化字符串
字符串键:print “%(key)s” % a_dict,调用 a_dict 中 key 对应的 value。
注意:
- a_dict 只以字符串作为 key;
- 括号(key)中的字符串格式的 key 不用加引号;
>>> phone_book = {'John':'0123', 'Lily':'1234', 'Tom':'2345', 'Robert':'3456'}
>>> print "Tom's phone number is %(Tom)s." % phone_book
Tom's phone number is 2345.
>>> print "%(Robert)s and %(Lily)s" % phone_book #后面只能跟一个字典
3456 and 1234
# 转换符 % 后面貌似只能跟一个字典,多个时加( )、顺次排列也行不通;
>>> address = {'John':'J', 'Lily':'L', 'Tom':'T', 'Robert':'R'}
>>> print "Tom's phone number is %(Tom)s and address is %(Tom)s" % (phone_book, address) #使用()排列多个字典也不行
TypeError: format requires a mapping
# 以上述电话簿为例
>>> user_info
{
'Matt': {'phone': '3456', 'addr': 'M'},
'John': {'phone': '0123', 'addr': 'J'},
'Robert': {'phone': '4567', 'addr': 'R'},
'Tom': {'phone': '1234', 'addr': 'T'}
}
>>> print "%(Matt[phone])s" % user_info
KeyError: 'Matt[phone]'
# 错误:Matt[phone]对应的是子字典Matt中的phone的 值,其不是user_info中的一个key;
>>> print "%(phone)s" % user_info['Matt']
3456
# 此时的 phone 是user_info['Matt']中的 key;
# user_info['Matt']对应的是Matt信息的子字典;
# 将上述电话簿例子中最后的print改为如下,则会出错:
>>> print "Matt's phone number is %(key)s." % user_info[name]
KeyError: 'key'
# 因为 key 本身不是 字符串,虽然 key = 'phone'(or address,此处为了方便)
# 故在字符串键中 key 必须是字符串,改为如下则正确了:
>>> print "Matt's phone number is %(phone)s." % user_info[name]
3 字典方法
3.1 clear
清除字典中所有项,无返回值
>>> a_dict = {}
>>> a_dict['name'] = 'John'
>>> a_dict['age'] = 23
>>> a_dict
{'age': 23, 'name': 'John'}
>>> a_dict.clear()
>>> a_dict
{}
考虑下面两种情况:
第一种情况
>>> a_dict = {'name':'John', 'age':23}
>>> b_dict = a_dict
>>> a_dict = {} #通过关联到空字典{}来清空a_dict
>>> a_dict
{}
>>> b_dict #但是对复制的b_dict没有影响
{'age': 23, 'name': 'Tom'}
第二种情况
>>> a_dict = {'name':'John', 'age':23}
>>> b_dict = a_dict
>>> a_dict.clear() #使用clear函数来清空字典
>>> a_dict
{}
>>> b_dict #复制的b_dict也没清空
>{}
3.2 copy
浅复制:替换副本中的 值 的时候,原字典不受影响;修改副本中 值 的时候,原字典也跟着改变;
>>> a_dict = {'name':'John', 'info':[23, 'Beijing', 'male']}
>>> b_dict = a_dict.copy()
>>> b_dict['name'] = 'Tom' #替换
>>> b_dict['info'].remove('male') #修改
>>> b_dict
{'info': [23, 'Beijing'], 'name': 'Tom'}
>>> a_dict
{'info': [23, 'Beijing'], 'name': 'John'}
深复制:副本与原字典间互不影响;
>>> from copy import deepcopy
>>> a_dict = {'name':'John', 'info':[23, 'Beijing', 'male']}
>>> b_dict = deepcopy(a_dict)
>>> a_dict['info'].append('rich')
>>> a_dict
{'info': [23, 'Beijing', 'male', 'rich'], 'name': 'John'}
>>> b_dict # a_dict 和 b_dict 互不影响
{'info': [23, 'Beijing', 'male'], 'name': 'John'}
3.3 fromkeys
使用给定的 键 创建字典,每个 键 默认对应的 值 为None.
>>> {}.fromkeys(['name', 'age', 'gender']) #方法1
{'gender': None, 'age': None, 'name': None}
>>> dict.fromkeys('name', 'address', 'phone') #方法2
TypeError: fromkeys expected at most 2 arguments, got 3
>>> dict.fromkeys(['name', 'age']) #【疑问】用方法2时最多有2个key
{'age': None, 'name': None}
#将 key 的值初始化
>>> dict.fromkeys(['name', 'age'], '(unknow)')
{'age': '(unknow)', 'name': '(unknow)'}
3.4 get
访问字典项的方法,即便 项 不存在,也不会出错.
>>> a_dict = dict.fromkeys(['name', 'age', 'gender'], 'hihi')
>>> a_dict['address']
KeyError: 'address'
>>> print a_dict.get('address')
None
>>> print a_dict.get('name')
hihi
【重要】a_dict.get(key, value)相当于一个if…else…语句——当key in a_dict,返回 key 对应的 值,当 key 不在字典中时,则返回提供的value——原文链接
>>> a_dict = {'name':'John', 'age':23}
>>> print a_dict.get('name', 'none') #key in a_dict
John
>>> print a_dict.get('address', 'error')#key 不在a_dict中
error
>>> a_dict
{'age': 23, 'name': 'John'}
以代码清单4-1 电话簿为例:
user_info = {
'John':{'phone':'0123','addr':'J'},
'Tom':{'phone':'1234','addr':'T'},
'Lily':{'phone':'2345','addr':'L'},
'Matt':{'phone':'3456','addr':'M'},
'Robert':{'phone':'4567','addr':'R'}
}
label = {
'phone':'phone number',
'addr':'address'
}
# 上述两个字典公用的 key 相同
# 获取用户需求
name = raw_input('Name: ')
choice = raw_input('The info you needed, phone number(P) or address(A): ')
key = choice # 当choice不是P或A时
if choice == 'P': key = 'phone'
if choice == 'A': key = 'addr'
person = user_info.get(name, {})
# 如果name in user_info, 则返回其name;反之,name = {}
phone_or_addr = label.get(key, key)
# 当key不在label中时,返回(从用户获得的)key
result = user_info[name].get(key, 'not available')
# 当key不存在与user_info[name]时,返回'not available'
print "%s's %s is %s." % (name, phone_or_addr, result)
--------------------------------------------------------------
运行结果:
Name: John
The info you needed, phone number(P) or address(A): P
John's phone number is 0123.
Name: Matt
The info you needed, phone number(P) or address(A): you choose
Matt's you choose is not available.
--------------------------------------------------------------
3.5 has_key
a_dict has_key(key) == key in a_dict;
python2.7.9中及3.0以后不支持该函数;
3.6 items and iteritems
- items将字典项以列表方式返回,列表中的每一项都来自(键,值);
- 【后续】items()和iteritems()方法都普遍用于for循环的迭代中,不同的是items()返回的是列表对象,而iteritems()返回的是迭代器对象。两者用法相近,但iteritems()的性能更快——原文链接
>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_list = a_dict.items()
>>> a_list
[('gender', 'male'), ('age', 23), ('name', 'John')]
>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_iterator = a_dict.iteritems()
>>> a_iterator
<dictionary-itemiterator object at 0x02325600>
>>> list(a_iterator) #将迭代器转换为list
[('gender', 'male'), ('age', 23), ('name', 'John')]
3.7 keys and iterkeys
keys 将字典中的 键 以列表形式返回,与 fromkeys 对应; iterkeys 则返回针对 键 的迭代器;>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_list = a_dict.keys()
>>> a_list
['gender', 'age', 'name']
>>> a_iterator = a_dict.iterkeys()
>>> a_iterator
<dictionary-keyiterator object at 0x023322D0>
>>> list(a_iterator)
['gender', 'age', 'name']
3.8 pop
pop 获取 key 对应的 value,并将key-value删除;>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_dict.pop('age')
23
>>> a_dict
{'gender': 'male', 'name': 'John'}
3.9 popitem
- popitem 返回并删除字典中随机的一 项,类似 list.pop(删除最后一项);
- 可以用于一个一个删除字典中的项;
>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_dict.popitem()
('gender', 'male')
>>> a_dict
{'age': 23, 'name': 'John'}
3.10 setdefault
- 当 键 存在的时候,setdefault 返回 key 对应的 value,不改变字典;
- 当 键 不存在的时候,setdefault 返回默认值并更新字典;
>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_dict.setdefault('phone', '1234') #key phone不存在
'1234'
>>> a_dict.setdefault('name', 'users') #key name存在
'John'
>>> a_dict
{'gender': 'male', 'age': 23, 'name': 'John', 'phone': '1234'}
3.11 update
update 利用一个字典项更新另一个字典;
>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> b_dict = {'name':'Tom'}
>>> a_dict.update(b_dict) # b_dict 中的 键 存在于 a_dict中
>>> a_dict
{'gender': 'male', 'age': 23, 'name': 'Tom'}
>>> c_dict = {'gender':'female', 'phone':'1234'}
# c_dict 中有 键 不在 a_dict 中,其对应的 项 会被更新到 a_dict 中
>>> a_dict.update(c_dict)
>>> a_dict
{'gender': 'female', 'age': 23, 'name': 'Tom', 'phone': '1234'}
3.12 values and itervalues
- values 以列表的形式返回字典中的 值,生成的列表可以包含重复值;
- itervalues 返回字典中 值 的迭代器;
>>> a_dict = {'name':'John', 'age':23, 'gender':'male'}
>>> a_dict.values()
['male', 23, 'John']
>>> a_dict
{'gender': 'male', 'age': 23, 'name': 'John'}
>>> a_dict.itervalues()
<dictionary-valueiterator object at 0x02325630>
>>> list(a_dict.itervalues())
['male', 23, 'John']
第四章 小节
- 映射:可以使用不可变元素(如key)表示元素,最常用的的时字符串和元组,python中唯一内建映射是字典;
- 利用字典格式化字符串:print “……%(key)s……” % a_dict,a_dict中的key必须都是字符串,括号中的key不加引号;
- 本章新函数:
>>> a_dict = dict(name='John', age='24')
>>> a_dict
{'age': '24', 'name': 'John'}
>>> b_dict = dict([('name', 'John'), ('age', '24')])
>>> b_dict
{'age': '24', 'name': 'John'}