字典
字典:当索引不好用时。
字典是python中唯一内建的映射类型。字典中的值并没有特殊的顺序,但是都存储在一个特定的键(key)下。键可以是数字、字符串甚至元组。
1.字典的使用
一下情况字典比列表更加适用,比如:
a.表示一个游戏盘的状态,每个键都是由坐标组成的元组;
b.存储文件修改时间,用文件作为键;
c.数字电话/地址薄
2.创建和使用字典
字典创建方式如下:
1 phonebook = {'Alice':'3241','Beth':'9102'}
字典有多个键及其对应的值构成的键-值对组成(我们把键-值对称为项),每个键和它的值之间使用冒号(:)隔开,项于项之间用逗号隔开。空字典由{}组成
注意:字典的键是唯一的(其他类型的映射也是如此),而值并不是唯一的。
1.dict函数
可以用dict函数(dict函数根本不是真正的函数,他是个类型),通过其他映射(比如其他字典)或者(键值)对的列表建立字典
1 >>> items = [('name','Gumby'),('age',42)] 2 >>> d = dict(items) 3 >>> d 4 {'name': 'Gumby', 'age': 42} 5 >>> d['name'] 6 'Gumby'
dict函数也可以通过关键字参数来创建字典,如下所示:
1 >>> d = dict(name='Gumby',age=42) 2 >>> d 3 {'name': 'Gumby', 'age': 42}
2.基本字典操作
字典的基本行为在很多方面与序列(sequence)类似:
- len(d)返回中项(键值对)的数量
- d[k]返回关联到键k的值
- d[k]=v将值v关联到键k上;
- del d[k]删除键k的项;
- k in d检查d中是否又含有键为K的项
尽管字典和列表有很多特性相同,但也有下面一些重要的区别。
- 键类型:字典的键不一定为整型数据,键可以是任意的不可变类型,比如浮点型(实型)、字符串或者元组。
- 自动添加:即使键起初在字典中并不存在,也可以为它赋值,这样字典就会建立新的项。而(在不适用append方法或者其他类似操作的情况下)不能将值关联到列表范围之外的索引上。
- 成员资格:表达式k in d(d为字典)查找的键,而不是值。表达式v in l(l为列表)则用来查找值,而不是索引。这样看起来好像有些不太一致,但是当习惯以后就会感觉非常自然了。
提示:在字典检查的成员资格比在列表中检查的成员资格更高效,数据结构的规模越大,两者的效率差距越明显。
第一点:键可以是任意不可变类型——是字典最为强大的地方。
第二点:举例说明,见一下例子
1 >>> x=[] 2 >>> x[42]='Foobar' 3 Traceback (most recent call last): 4 File "<stdin>", line 1, in <module> 5 IndexError: list assignment index out of range 6 >>> x = {} 7 >>> x[42]='Foobar' 8 >>> x 9 {42: 'Foobar'}
首先,程序试图将字符串‘Foobar’关联到一个空列表的42号位置上——这显然是不可能的,应为这个位置根本不存在。为了将其变得可能,必须用[None]*43或者其他方法初始化x,而不能仅使用[]。但是,下一个例子工作得很好。将'Foobar'关联到空字典的键42上(能成功加入,这也说明了字典的无序性),结果成功加入。
电话本例子的代码如下:
1 #!/usr/bin/env python 2 # -*- coding:utf-8-*- 3 people = { 4 'Alice': { 5 'phone': '2341', 6 'addr': 'Foo drive 23' 7 }, 8 'Beth': { 9 'phone': '9120', 10 'addr': 'Bar street 43' 11 }, 12 'Cecil': { 13 'phone': '3158', 14 'addr': 'Baz avenue 90' 15 } 16 } 17 # 针对电话号码和地址使用的描述性标签,输出时使用到 18 labels = { 19 'phone': 'phone number', 20 'addr': 'address' 21 } 22 # 输出所有用户的名字 23 print(people.keys()) 24 25 # 提示用户数据要查找的姓名 26 name = input('Name: ') 27 28 print(people[name].values()) 29 # 查找电话号码还是地址 30 request = input('Phone Number(p) or Address(a)?') 31 # 根据使用的键,做对应输出: 32 if request == 'p': key = 'phone' 33 if request == 'a': key = 'addr' 34 35 # 最后输出校验,如果名字是字典中有效键才打印信息 36 if name in people:print( "%s's %s is %s."%\ 37 (name,labels[key],people[name][key])) 38 39 运行结果如下: 40 dict_keys(['Cecil', 'Beth', 'Alice']) 41 Name: Cecil 42 dict_values(['Baz avenue 90', '3158']) 43 Phone Number(p) or Address(a)?p 44 Cecil's phone number is 3158.
3.字典的格式化字符串
使用字典(只以字符串作为键的)而不是元组,会使字符串格式化更简单更酷一些。在每个转换说明符中的%字符后面,可以加上键(用圆括号括起来),后面再跟上其他说明元素。
示例如下:
1 >>> phonebook={'Beth':'9102','Alice':'2314','Cecil':'3258'} 2 >>> "Cecil's phone number is %(Cecil)s."%phonebook 3 "Cecil's phone number is 3258."
除了增加的字符串键之外,转换说明符还是像以前一样工作。当以这种方式使用字典的时候,只要所有给出的键都能在字典中找到,就可以使用任意数量的转换说明符。这类字符串格式化在模板系统中非常有用。如下示例:
__author__ = 'Administrator' template = ''' <html> <head><title>%(title)s</title></head> <body> <h1>%(title)s</h1> <p>%(text)s</p> </body> </html> ''' data = {'title':'My Home Page','text':'Welcome to my home page!'} print(template%data) 运行结果如下: <html> <head><title>My Home Page</title></head> <body> <h1>My Home Page</h1> <p>Welcome to my home page!</p> </body> </html>
注意:string.Template类对于这类应用也是非常用用的。
4.字典方法
4.1 clear
clear方法清除字典中所有的项。这是原地操作(类似于list.sort),所以无返回值(或者说返回None)如下示例
1 >>> d = {} 2 >>> d['name']='Gumby' 3 >>> d['age']=23 4 >>> d 5 {'name': 'Gumby', 'age': 23} 6 >>> returned_value = d.clear() 7 >>> d 8 {} 9 >>> returned_value 10 >>> print(returned_value) 11 None
4.2 copy
copy方法返回一个具有相同键值对的新字典(这个方法实现的是浅复制(shallow copy),应为值本身就是相同的,而不是副本)。
1 >>> x = {'username':'admin','machines':['foo','bar','baz']} 2 >>> y = x.copy() 3 >>> y['username'] = 'mlh' 4 >>> y 5 {'machines': ['foo', 'bar', 'baz'], 'username': 'mlh'} 6 >>> y['machines'].remove('bar') 7 >>> y 8 {'machines': ['foo', 'baz'], 'username': 'mlh'} 9 >>> x 10 {'machines': ['foo', 'baz'], 'username': 'admin'}
可以看到,当在副本中替换值是,原始字典不受影响,但是,如果修改了某个值(原地修改,而不是替换),原始字典也会改变。因为同样的值也存在原字典中(就像上面例子中的machine列表一样)。
避免这个问题的一种方法就是使用深复制(deep copy),复制其包含的所有值。可以使用copy模块中的deepcopy函数来完成操作:
1 >>> from copy import deepcopy 2 >>> d = {} 3 >>> d['names'] = ['Alfred','Bertrand'] 4 >>> c = d.copy() 5 >>> dc = c.deepcopy(d) 6 Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8 AttributeError: 'dict' object has no attribute 'deepcopy' 9 >>> dc = deepcopy(d) 10 >>> d['names'].append('Clive') 11 >>> c 12 {'names': ['Alfred', 'Bertrand', 'Clive']} 13 >>> dc 14 {'names': ['Alfred', 'Bertrand']}
4.3 fromkeys
fromkeys方法使用给定的键值建立新的字典,每个键都对应一个默认的值None.
1 >>> {}.fromkeys(['name','age']) 2 {'name': None, 'age': None}
4.4 get
get方法是个更宽松的访问字典项的方法。一般来说,如果试图访问字典中不存在的项时会出错:
1 >>> d = {} 2 >>> print(d['name']) 3 Traceback (most recent call last): 4 File "<stdin>", line 1, in <module> 5 KeyError: 'name'
>>> d = {}
>>> print(d['name'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'name'
#而用get就不会
>>> print(d.get('name'))
None
字典方法示例
1 #字典方法示例(get) 2 #使用get()的简单数据库 3 lables = { 4 'phone':'phone number', 5 'addr':'address' 6 } 7 8 name = input('Name:') 9 10 #查找电话号码还是地址? 11 request = input('Phone number(p) or address(a)? ') 12 13 #使用正确的键 14 key = request # 如果请求既不是'p'也不是'a' 15 if request=='p':key = 'phone' 16 if request=='a':key = 'address' 17 18 #使用get()提供默认值 19 people = {} 20 person = people.get(name,{}) 21 lable = lables.get(key,key) 22 result = person.get(key,'not available') 23 24 print("%s's %s is %s."%(name,lable,result)) 25 26 ================================= 27 运行结果如下: 28 Name:tom 29 Phone number(p) or address(a)? s 30 tom's s is not available.
4.5 items和iteritems
items方法将字典所有的项以列表方式返回,列表中的每一项都表示对应的形式。但是项再返回时并没有遵循特定的秩序。
iteritems方法的作用大致相同,但返回一个迭代器对象而不是列表。
4.6 pop
pop方法用来获得对应对于给定键的值,然后将这个键-值对从字典中移除。
4.7 popitem
popitem方法类似于list.pop,后者会弹出列表的最后一个元素。但不同的是,popitem弹出随机的项,因为字典并没有“最后的元素”或者其他有关顺序的概念。若想一个接一个的移除并处理项,这个方法就非常有用了(因为不用首先获取键的列表)。
1 >>> d = {'url':'http://www.python.org','span':0,'title':'Python Web Site'} 2 >>> d.popitem() 3 ('span', 0) 4 >>> d 5 {'title': 'Python Web Site', 'url': 'http://www.python.org'}