第四章: 字典-当索引不好用时
在本章,将学到通过名字来引用值的数据结构。这种类型的数据结构成为映射(mapping)。
字典是python中唯一内建的映射类型。
字典中的值并没有特殊的顺序,但都是存储在一个特定的键(key)下。键可以是数字、字符串甚至是元祖。
字典的使用
某些情况下,字典比列表更加适用,比如:
标示一个棋盘的状态,每个键都是由坐标组成的元祖;
存储文件修改时间,用文件名作为键;
数字电话/地址簿
>>>010
8
这并不是10,因为,八进制数字均是以0为开头的。
教训就是:电话号码(以及其他可能以0
开头的数字)应该表示为数字字符串,而不是整数。
创建和使用字典
字典由多个键与其对应的值构成的键-值对组成(我们也把键-值对称为项)。
**注:字典中的键是唯一的(其他类型的映射也是如此),而值并不是唯一。
>>>a={'a':1,'b':2,'a':3}
>>>a
{'a':3,'b':2}
dict函数
可以用dict
函数(dict函数不是真正的函数,它是个类型,就像list,tuple,str一样)。通过其他映射(比如其他字典)或者(键,值)对的序列建立字典。
>>>items=[('name','Michael'),('age',42)]
>>>d=dict(items)
>>>d
{'age':42,'name':'Michael'}
dict
函数也可以通过关键字参数来创建字典。
>>>d = dict(name='Micahel',age=42)
>>>d
{age:42,'name':'Michael'}
基本字典操作
字典的基本行为在很多方面与序列(sequence)类似:
len(d)返回d中项(键-值对)的数量;
d[k]返回关联到键k上的值;
del d[k]删除键为k的项
k in d检查d中是否含有键为k的项
尽管字典和列表有很多特性相同,但也有下面的一些重要区别:
键类型:字典的键不一定是整型数据(但也可以是),键可以是任意的不可变类型,比如浮点型(实型)、字符串或者元祖。
自动添加:即使键起初在字典中不存在,也可以为他赋值,这样字典就会建立新的项。而(在不使用
append
方法或者其他类似操作的情况下)不能将值关联到列表范围之外的索引上。成员资格:表达式k in d(d为字典)查找的是键,而不是值。表达式v in L (L为列表)则用来查找值,而不是索引。
第一点——键可以是任意不可变类型——是字典最强大的地方。
>>>x=[]
>>>x[42]='michael'
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-6-a517a7857c71> in <module>()
1 x=[]
----> 2 x[42]='michael'
IndexError: list assignment index out of range
>>>x={}
>>>x[42]='Michael'
>>>x
{42:'Michael'}
字典的格式化字符串
在每个转换说明符(conversion specifier)中的%字符后面,可以加上键(用圆括号括起来的),后面再跟上其他说明元素。
>>>phonebook={'michael':'123','hh':234}
>>>"michaelis phone number is %(michael)s."%phonebook
'michaelis phone number is 123'
这类字符串格式化在模板系统中非常有用。
字典方法
clear
clear
方法清除字典中所有的项。 这个原地操作(类似list.sort),所以无返回值(或者说返回None)。
为什么这个方法有用呢?考虑一下两种情况:
栗子1:
>>>x = {}
>>>y = x
>>>x['key']='value'
>>>y
{'key':'value'}
>>>x = {}
>>>y
{'key':'value'}
栗子2:
>>>x = {}
>>>y = x
>>>x['key']='value'
>>>y
>>>x.clear()
>>>y
{}
其实归根结底,记住clear
方法跟sort
方法一样,没有返回值。
copy
copy
方法返回一个觉有相同键-值对的新字典(这个方法实现的是浅复制(shallow copy),因为值本身就是相同的,而不是副本)。
>>>x={'a':1,'b':[1,2,3]}
>>>y=x.copy()
>>>x['a']=0
>>>print x
{'a': 0, 'b': [1, 2, 3]}
>>>print y
{'a': 1, 'b': [1, 2, 3]}
>>>y['b'].append(4)
>>>print x
{'a': 0, 'b': [1, 2, 3, 4]}
>>>print y
{'a': 1, 'b': [1, 2, 3, 4]}
通过上图的执行顺序可以看出,对于字典中的值,他们是分立的,互相不影响;但是,字典中值是引用型的,他们就会互相影响。从上面的动态图也可以猜想,浅复制并不是完全复制,y并不是完全和x分隔的副本。原始字典中值存在例如列表这样的引用型传递的,那么,y中存储的值就是引用型传递的结果,存储的是和x中引用型值一样。
反正自己这么理解,可以解释通得到的结果。
通过这么理解,写了另外一个栗子:
>>>x={'a':1,'b':[1,2,3]}
>>>y=x.copy()
>>>x['a']=0
>>>print x
{'a': 0, 'b': [1, 2, 3]}
>>>print y
{'a': 1, 'b': [1, 2, 3]}
>>>y['b']=['m','n']
>>>print x
{'a': 0, 'b': [1, 2, 3, 4]}
>>>print y
{'a': 1, 'b': ['m','n']}
避免出现这样问题的一种方法就是深复制(deep copy),复制其包含的所有值。可以使用copy模板的deepcopy
函数来完成。就不举例了。
浅复制参考文档:
fromkeys
fromkeys
方法使用给定的键建立新的字典,每个键都对应一个默认的值None。
>>>{}.fromkeys(['name','age'])
{'age':None,'name':None}
此外,还可以直接在dict
上面调用该方法,前面讲过,dict
是所有字典的类型。
>>>dict.fromkeys(['name','age'])
{'age':None,'name':None}
如果不想使用None作为默认值,也可以自己提供默认值。
>>>dict.fromkeys(['name','age'],'(unknown)')
{'age': '(unknown)', 'name': '(unknown)'}
get
get
方法是个更宽松的访问字典项的方法。一般说来,如果试图访问字典中不存在的项时会出错:
>>>d = {}
>>>print d['name']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-11-4f402a46f272> in <module>()
1 d={}
----> 2 print d['name']
KeyError: 'name'
>>>print d.get('name') #用get方法就不会
None
>>>d.get('name','N/A') #还可以自定义默认值
'N/A'
haskey
haskey
方法可以检查字典中是否含有特定的键。表达式d.haskey(k)相当于表达式k in d。使用哪个方式取决于个人喜好。python3.0中不包括这个函数。
items和iteritems
items
方法将字典所有的项以列表方式返回,列表中的每一项都表示为(键,值)对的形式。
>>>d={'title':'test','name':'michael','age':24}
>>>d.items()
[('age', 24), ('name', 'michael'), ('title', 'test')]
itritems
方法的作用大致相同,但是会返回一个迭代器对象而不是列表:
>>>it = d.iteritems()
>>>it
<dictionary-itemiterator at 0x3262ea0>
>>>list(it)
[('age', 24), ('name', 'michael'), ('title', 'test')]
在很多情况下,iteritems
方法效果会更加高(尤其是想要迭代结果的情况下)。参考第九章。
keys和iterkeys
keys
方法将字典中的键以列表形式返回。iterkeys
则返回针对键的迭代器。
pop
pop
方法用来获得对应于给定键的值,然后将这个键-值对从字典中移除。
>>>d = {'a':1,'b':2}
>>>d.pop('a')
1
>>>d
{'b':2}
popitem
popitem
方法类似于list.pop
,后者会弹出列表的最后一个元素。但不同的是,popitem
弹出随机的项,因为字典并没有”最后的元素"或者其他有顺序的概念!!!
若想要一个接一个地移除并处理项,这个方法就非常有效了(因为不用首先获取键的列表)。
>>>d = {'a':1,'b':2}
>>>d.popitem()
('a', 1)
>>>d
{'b':2}
setdefault
setfault
方法在某种程度上类似于get
方法,能够获得给定键相关联的值。不同的地方时,setdefault
还能在没有对应键存在的情况下,设定相应的键。
>>>d={}
>>>d.setdefault('name','N/A') #如果对应键存在,那么久返回键关联的值。默认是可选的。
'N/A'
update
update
方法可以利用一个字典项更新另外一个字典。
>>>a={'x':1,'y':2,'z':3}
>>>b={'x':0}
>>>a.update(b)
>>>a
{'x':0,'y':2,'z':3}
如果有相同的键,则会进行覆盖。如果没有相同键,则会添加!
values和itervalus
values
方法以列表的形式返回字典中的值(itervalues返回值的迭代器)
本章小结
映射:映射可以使用任意不可变对象标识元素。最常用的类型是字符串和元祖。python唯一内建的映射类型是字典。
-
浅复制(shallow copy)和深复制(deepcopy):本来是比较小的知识点,基础教程中也没有深入讲解一下为何是这样的结果,由于没太看明白,查资料,还是有收获的!希望以后能有资料更深入了解一下~
元旦节日,教研室人气不高,反倒是感觉挺好~加油~坚持下去!