在本章,将学到通过名字来引用值的数据结构。这种类型的数据结构成为映射(mapping)。
字典是python中唯一内建的映射类型。
字典中的值并没有特殊的顺序,但都是存储在一个特定的键(key)下。键可以是数字、字符串甚至是元祖。
某些情况下,字典比列表更加适用,比如:
标示一个棋盘的状态,每个键都是由坐标组成的元祖;
存储文件修改时间,用文件名作为键;
数字电话/地址簿
>>>010
8
这并不是10,因为,八进制数字均是以0为开头的。
教训就是:电话号码(以及其他可能以0
开头的数字)应该表示为数字字符串,而不是整数。
字典由多个键与其对应的值构成的键-值对组成(我们也把键-值对称为项)。
**注:字典中的键是唯一的(其他类型的映射也是如此),而值并不是唯一。
>>>a={\'a\':1,\'b\':2,\'a\':3}
>>>a
{\'a\':3,\'b\':2}
可以用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)
in ()
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
方法清除字典中所有的项。 这个原地操作(类似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
方法返回一个觉有相同键-值对的新字典(这个方法实现的是浅复制(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
函数来完成。就不举例了。
浅复制参考文档:
深入Python(4):深拷贝和浅拷贝
官方:copy — Shallow and deep copy operations
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
方法是个更宽松的访问字典项的方法。一般说来,如果试图访问字典中不存在的项时会出错:
>>>d = {}
>>>print d[\'name\']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
in ()
1 d={}
----> 2 print d[\'name\']
KeyError: \'name\'
>>>print d.get(\'name\') #用get方法就不会
None
>>>d.get(\'name\',\'N/A\') #还可以自定义默认值
\'N/A\'
haskey
方法可以检查字典中是否含有特定的键。表达式d.haskey(k)相当于表达式k in d。使用哪个方式取决于个人喜好。python3.0中不包括这个函数。
items
方法将字典所有的项以列表方式返回,列表中的每一项都表示为(键,值)对的形式。
>>>d={\'title\':\'test\',\'name\':\'michael\',\'age\':24}
>>>d.items()
[(\'age\', 24), (\'name\', \'michael\'), (\'title\', \'test\')]
itritems
方法的作用大致相同,但是会返回一个迭代器对象而不是列表:
>>>it = d.iteritems()
>>>it
>>>list(it)
[(\'age\', 24), (\'name\', \'michael\'), (\'title\', \'test\')]
在很多情况下,iteritems
方法效果会更加高(尤其是想要迭代结果的情况下)。参考第九章。
keys
方法将字典中的键以列表形式返回。iterkeys
则返回针对键的迭代器。
pop
方法用来获得对应于给定键的值,然后将这个键-值对从字典中移除。
>>>d = {\'a\':1,\'b\':2}
>>>d.pop(\'a\')
1
>>>d
{\'b\':2}
popitem
方法类似于list.pop
,后者会弹出列表的最后一个元素。但不同的是,popitem
弹出随机的项,因为字典并没有”最后的元素\”或者其他有顺序的概念!!!
若想要一个接一个地移除并处理项,这个方法就非常有效了(因为不用首先获取键的列表)。
>>>d = {\'a\':1,\'b\':2}
>>>d.popitem()
(\'a\', 1)
>>>d
{\'b\':2}
setfault
方法在某种程度上类似于get
方法,能够获得给定键相关联的值。不同的地方时,setdefault
还能在没有对应键存在的情况下,设定相应的键。
>>>d={}
>>>d.setdefault(\'name\',\'N/A\') #如果对应键存在,那么久返回键关联的值。默认是可选的。
\'N/A\'
update
方法可以利用一个字典项更新另外一个字典。
>>>a={\'x\':1,\'y\':2,\'z\':3}
>>>b={\'x\':0}
>>>a.update(b)
>>>a
{\'x\':0,\'y\':2,\'z\':3}
如果有相同的键,则会进行覆盖。如果没有相同键,则会添加!
values
方法以列表的形式返回字典中的值(itervalues返回值的迭代器)
映射:映射可以使用任意不可变对象标识元素。最常用的类型是字符串和元祖。python唯一内建的映射类型是字典。
浅复制(shallow copy)和深复制(deepcopy):本来是比较小的知识点,基础教程中也没有深入讲解一下为何是这样的结果,由于没太看明白,查资料,还是有收获的!希望以后能有资料更深入了解一下~
深入Python(4):深拷贝和浅拷贝
官方:copy — Shallow and deep copy operations
stackoverflow浅复制问题
元旦节日,教研室人气不高,反倒是感觉挺好~加油~坚持下去!