第四章 当索引行不通时
第四章 当索引行不通时
需要将一系列值组合成数据结构并通过编号来访问各个值时,列表很有用。本章将介绍一种可通过名称来访问其各个值的数据结构。这种数据结构称为映射(mapping)。字典是Python中唯一的内置映射的类型,其中的值不按顺序,而是存储在键下。键可能是数,字符串或元组。
4.1、字典的用途
字典的名称指出了这种数据结构的用途。字典旨在让你轻松地找到特定的单词(键),以获悉其定义(值)。
在很多情况下,使用字典都较为的合适。下面是Python字典的一些用途:
- 表示棋盘的状态,其中每个键都是由坐标组成的元组;
- 存储文件修改时间,其中的键为文件名;
- 数字电话/电话薄
4.2、创建和使用字典
字典以类似于下面的方式表示:
phonebook = {‘Alice’:‘2341’,‘Beth’:‘9102’,‘Ceil’:‘3258’}
字典由键及其相应的值组成,这种键-值对称为项(item)。在前面的示例中,键为名字,而值为电话号码。每个键与其值之间冒号( :)分隔,项之间用逗号分隔,而整个字典放在花括号内。空括号(没有任何项)用两个花括号表示,类似于下面这样:{ }。
注意:在字典(以及其他映射类型)中,键必须是独一无二的,而字典中的值无需如此。
4.2.1 函数dict
可使用函数dict从其他映射(如其他字典)或键-值对序列创建字典。
>>>items=[('name','Gumby'),('age',42)]
>>>d=dict(items)
>>>d
{'age':42,'name':'Gumby'}
>>>d['name']
'Gumby'
还可使用关键字实参来调用这个函数,如下所示:
>>>d=dict(name='Gumby',age=42}
>>>d
{'age':42,'name':GUmby'}
尽管这可能是函数dict最常见的用户,但也可使用一个映射实参来调用它,这将创建一个字典,其中包含指定映射中的所有项。像函数list、tuple和str一样,如果调用这个函数时没有提供任何实参,将返回一个空字典。从映射创建字典时,如果该映射也是字典(毕竟字典时Python中唯一的内置映射类型),可不使用函数dict,而是使用字典方法copy,这将在本章后面介绍。
4.2.2 基本字典操作
字典的基本行为在很多方面都类似于序列:
- len(d)返回字典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是列表)查找的是值而不是索引。
提示:相比于检查列表是否包含指定的值,检查字典是否包含指定的键效率更高。数据结构越大,效率差距就越大
上述中已经提到了关于字典的第一个优点:键可以是任何不可变的类型;关于第二点,将会从下面的例子讲出来:
x=[] x[42]='foobar'
上述的结果会出现下面的结果,思考一下,为什么会出现这种现象:
Traceback (most recent call last): File "G:/Py_project/Python基础教程/字典.py", line 2, in <module> x[42]='foobar' IndexError: list assignment index out of range
而针对字典的时候,我们在使用上述的方法的时候,显然,这种方法就能够正确的运行
x={} x[42]='foobar' print(x)
计算机将会运行处不一样的结果:
{42: 'foobar'}
这是因为在列表中,Python中列表中的元素就像C语言中的数组一样,需要按顺序存放,里面分配多少空间才能够用多少空间,而字典就不太一样,字典则会分配成键和值,然后相对来说,如何使上述能的列表输入正常,则需要通过列表中的None方法:
y=[None]*43 y[42]='foobar' print(y)
然后,结果就能够被输出:
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'foobar']
本文在下面进行了一个简单的Python案例:
为字典案例:
people={ 'Alice':{ 'phone':'2341', 'addr' :'Foo drive 23' }, 'Beth' :{ 'phone':'9102', 'addr' :'Bar street 42' }, 'Cecil' : { 'phone':'3158', 'addr' :'Baz avenue 90' } } #电话号码和地址的表述性标签,供打印的时候使用 labels={ 'phone':'phone number', 'addr' :'address' } name=input('Name:') #要查找电话号码还是地址 request =input('Phone number(p) or address(a)?') #使用正确的键: if request =='p': key ='phone' if request =='a': key='addr' # 仅当名字是字典包含的键时才打印信息 if name in people : print("{}'s {} is {}".format(name,labels[key],people[name][key]))
这样,当你输入一定的值得时候,结果就会出现以下结果:
Name:Beth Phone number(p) or address(a)?a Beth's address is Bar street 42
4.2.3将字符串格式设置功能用于字典
在第三章,,我们都是使format方法通过命名或者非命名参数提供给方法format的,在字典中我们也能应用这种方法,下面举两个例子:
举例:
phonebook={'Beth':'9102','Alice':'2341','Cecil':'3258'} print("Cecil's phone number is {Cecil}.".format_map(phonebook))
这个例子将会出现下面这样的结果:
Cecil's phone number is 3258.
像这样的字典,我们可以使用任意数量的字典转换说明符,注意在这声明条件:所有的字段名都是包含在字典中的键。在模板系统中,这很有用,以HTML举例说明。
template ='''<html> ...<head><title>{title}</title></head> ...<body> ...<h1>{title}</h1> ...<p>{text}</p> ...<body>''' data={'title':'My Home Page','text':'Welcome to my home Page'} print(template.format_map(data))
然后出来的效果是:
<html> ...<head><title>My Home Page</title></head> ...<body> ...<h1>My Home Page</h1> ...<p>Welcome to my home Page</p> ...<body>
4.2.4 字典方法
与其他内置类型一样,字典也有方法。但没有列表和字符串的方法那样高。大致浏览了解即可。
1.clear
方法clear删除所有的字典项,这种操作是就地执行(就像list.sort一样).因此什么都不返回(或者说返回None)。
d={} d['name']='Gumby' d['age']= 42 print(d) returned_value =d.clear() print(d)
让我们看看这个程序运行的结果,与我们预期是否一致:
{'name': 'Gumby', 'age': 42} {}
显然是成立的,清空了所有的列表元素。那么在那种场景能够用到,下面我们来看看的这两种情况:
x={} y = x x['key']='value' x={} print(x) print(y)
看看输出的结果:
{} {'key': 'value'}
看看第二个例子:
x={} y=x x['key']='value' print(y) x.clear() print(y)
紧接着,我们看看第二个例子所得到的结果:
{'key': 'value'} {}
你会发现,y的值也被随之清空,那么,现在谈一谈我对这方面的理解,其实两种情况都是x与y指向相同的字典,通过第一个空字典赋给x来清空‘它。这对于y没影响,但用clear,y也将变为空,这个就是清除clear的所有内容。
2.copy和deepcopy
方法copy只是返回一个新的字典,其包含的键-值对于原本的字典相同(这种方法执行的是浅复制,因为值本身是原件,而非副本,但对于值为列表的时候,只是使它找到的地址相同,所以仍然在被修改的过程中都能够修改)
x={'username':'admin','machines':['foo','bar','baz']} y=x.copy() y['username']='mlh' y['machines'].remove('baz') print(x) print(y)
结果可想而知:
{'username': 'admin', 'machines': ['foo', 'bar']} {'username': 'mlh', 'machines': ['foo', 'bar']
但深复制不太一样,即它是复制值以及包含所有项的值甚至是他记录地址的值也会被复制,下面举个例子我们来比较一下:
from copy import deepcopy d={} d['name']=['Alfred','Bertrand'] c=d.copy() dc=deepcopy(d) d['name'].append('Clive') print(c) print(dc)
从而比较一下结果:
{'name': ['Alfred', 'Bertrand', 'Clive']} {'name': ['Alfred', 'Bertrand']}
3.fromkeys
方法fromkeys创建一个新的字典,包含指定的键且每个键的值都为None.
print({}.fromkeys(['name','age']))
得到的结果为:
print({}.fromkeys(['name','age']))
如果不想像上面那么麻烦,则可以直接使用dict:
print(dict.fromkeys(['name','age']))
从而得到结果为:
{'name': None, 'age': None}
如果不想使用默认值,可指定默认值
print(dict.fromkeys(['name','age'],'(unknown)'))
从而得到结果为:
{'name': '(unknown)', 'age': '(unknown)'}
4.get
通常情况下,如果你试图访问字典没有的项,会显示错误:
d={} print(d['name'])
错误结果如下:
Traceback (most recent call last): File "G:/Py_project/Python基础教程/字典.py", line 2, in <module> print(d['name']) KeyError: 'name'
但如果你使用get方法的情况下,就不会出现上述的问题,没有引发异常,而是返回None,如果想返回你指定的内容,也可在get中自己设置:
d={} print(d.get('name'))
结果为:
None
如果是自己指定的返回值,即为如下代码:一个为输入,一个为结果:
d={} print(d.get('name','N/A'))
N/A
这里在举一个简单的字典的方法示例:
people={ 'Alice':{ 'phone':'2341', 'addr':'Foo drive 23' }, 'Beth':{ 'phone':'9102', 'addr':'bar street 42' }, 'Cecil':{ 'phone':'3158', 'addr':'Baz avenue 90' } } labels={ 'phone':'phone number', 'addr':'address' } name=input('name:') #要查找电话号码还是地址 request=input('Phobe number(p) or address(a)?') #使用正确的键 if request=='p': key='phone' if request=='a': key='addr' #使用get提供默认值 person=people.get(name,{}) label=labels.get(key,key) result=person.get(key,'not available') print("{}'s {} is {}".format(name,label,result))
从而能够去验证,验证的结果下面:
name:Gumby Phobe number(p) or address(a)?p Gumby's phone number is not availed
5.items
方法items返回一个包含所有字典项的列表,其中每个元素都为(key,value)的形式(注意:排列顺序不确定),形式如下:
d={'add':['hehe','haha'],'title':'Python Web Site','url':'http://www.python.org','spam':0} print(d.items())
这种形式会返回一种字典视图,结果如下:
d={'add':['hehe','haha'],'title':'Python Web Site','url':'http://www.python.org','spam':0} print(d.items())
当然根据字典视图,我们有一些相应的操作,比如可用于迭代(关于迭代在第五章节),另外,还可确定其长度以及执行成员资格检查,下面就是关于这个的示例:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} it=d.items() print(len(it)) print(('spam',0) in it)
结果显而易见:
3 True
注意:在文章中,提到了有意思的地方为:视图不可复制,记住,不可以被复制,它只是作为底层字典的一种反映,修改底层的字典就能够被反映出来:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} it=d.items() print(('spam',0) in it) d['spam']=1 print(('spam',0) in it) d['spam']=0 print(('spam',0) in it)
让我们 来看看结果:
True False True
这的确印证了我们上面的注意项。当然,除了上面的功能,我们也同样可以将字典视图映射为列表:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} print(list(d.items()))
此时的结果为:
[('title', 'Python Web Site'), ('url', 'http://www.python.org'), ('spam', 0)]
6.keys
方法keys返回一个字典视图,其中包含指定字典的键,举个简单的例子:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} print(d.keys())
本身就会返回一个字典视图:
dict_keys(['title', 'url', 'spam'])
7.pop
方法pop用于删除你指定键的值,从字典中删除,举例说明:
d={'x':1,'y':2} d.pop('x') print(d)
从而得到结果为:
{'y': 2}
8.popitem
popitem称为随机删除,不指定键随机删除:
d={'x':1,'y':2} d.popitem() print(d)
查看结果为:
{'x': 1}
9.setdefault
这个我刚问感觉很有用,有点像get,其实区别就是setdefault对于你指定的键,如果没有,将其添加进入字典,并返回默认值给你,注意,如果你在setdefault里面设置了默认值,返回你的,如果没有,返回None;当然,如果有直接返回给你。举个例子:
d={} print(d.setdefault('name','N/A')) print(d) d['name']='Gumby' print(d.setdefault('name','N/A'))
从而得到结果为:
N/A {'name': 'N/A'} Gumby
10.update
update的中文意思为更新,其实就是使用一个字典中的项去更新另外一个字典:
d={ 'title':'Python Web Site', 'url':'http://www.python.org', 'changed':'Mar 14 22:09:15 MET 2016' } x={'title':'Python Language Website'} d.update(x) print(d)
从而,得到下面的结果:
{'title': 'Python Language Website', 'url': 'http://www.python.org', 'changed': 'Mar 14 22:09:15 MET 2016'}
注意:通过参数提供的字典,将其项添加到当前的字典中。如果当前字典包含的键相同的值,就替换它。
本章节,我有一点不理解的地方就是:就是这个update的最后一句话:可像调用本章前面讨论的函数dict(类似构造函数)那样调用函数update。这意味着调用update时,可向它提供一个映射、一个由键-值对组成的序列(或者其他可迭代对象)或者关键字。
11.value
方法values返回一个由字典中的值组成的字典视图。不同于方法keys,方法values返回的视图可能包含重复的值。举个例子进行说明:
d={} d[1]=1 d[2]=2 d[3]=3 d[4]=1 print(d)
然后在采用:
print(d.values())
最后得到结果为:
{1: 1, 2: 2, 3: 3, 4: 1} dict_values([1, 2, 3, 1])