第4章 字典:当索引不好用时
Posted 草丛抡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第4章 字典:当索引不好用时相关的知识,希望对你有一定的参考价值。
通过名字引用值的数据结构,这种结构类型称为映射(mapping)。字典是Python中唯一内建的映射类型。字典中的值并没有特殊的顺序,但是都存储在一个特定的键(key)里。键可以是数字、字符串甚至是元组。
4.1 字典的使用
现实中的字典及在Python中的字典都进行了构造,从而可以轻松查到某个特定的词语(key),从而找到它的定义(值)。
某些情况下,字典比列表更加适用,比如:
1.表征游戏棋盘的状态,每个键都是由坐标值组成的元组;
2.存储文件修改次数,用文件名作为键;
3.数字电话/地址簿
使用列表实现根据人名查找电话号码的需求:
>>> names = ["Alex","Beth","Cecil","Earl"] >>> numbers = ["2341","9102","3158","5551"] >>> numbers[names.index("Cecil")] \'3158\'
这样做虽然可行,但是并不实用。假如phonebook是一个字典,Cecil是一个key,就会如下查询:
>>> phonebook["Cecil"] 3158
4.2 创建和使用字典
字典可以通过下面的方式创建:
>>> phonebook = {"Alex":"2341","Bech":"9102","Cecil":"3158"}
字典由多个键及与其对应的值构成的对组成(键key/值values)。例子中,名字是键,电话号码是值。每个键和它的值之间用冒号(:)隔开,项之间用逗号(,)隔开,而整个字典是由一对大括号括起来。空字典(不包括任何项)由两个大括号组成,{}。字典中的键是唯一的,而值并不唯一。
4.2.1 dict函数
可以用dict函数,通过其他映射(比如其他字典)或者(键,值)这样的序列对建立字典。
>>> items = [("name","alex"),("age","23")] >>> d = dict(items) >>> d {\'name\': \'alex\', \'age\': \'23\'} >>> d["name"] \'alex\'
dict函数也可以通过关键字参数来创建字典,如下列所示:
>>> d = dict(name="alex",age=23) >>> d {\'name\': \'alex\', \'age\': 23}
4.2.2 基本字典操作
字典的基本行为在很多方面与序列(sequence)类似:
1.len(d)返回字典d中项(键-值对)的数量;
2.d[k]返回关联到键k上的值;
3.d[k]=v将值v关联到键k上;
4.del d[k]删除键k的项;
5.k in d检查d中是否含有键k的项。
尽管字典和列表有很多特性相同,但也有下面一些重要的区别。
1.键类型:字典的键不一定为整数类型(但也可能是),也可能是其他不可变类型,比如浮点型(实型)、字符串或者元组。
2.自动添加:即使键在字典中不存在,也可以为它分配一个值,建立新的项。而列表(不使用append或其他类似操作的情况下)不能将值关联到列表范围之前的索引上。
3.成员资格:表达式k in d(d为字典)查找的是键,而不是值。表达式v in l(l为列表)则用来查找值,而不是索引。
>>> x = [] >>> x[42] = "Foobar" Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list assignment index out of range >>> x = {} >>> x[42] = "Foobar" >>> x {42: \'Foobar\'} >>>
代码清单4-1是电话本例子的代码:
#简单的名称、电话、地址数据库,根据输入的人名,查找对应的电话号码或者地址 people = { "alex":{ "phone":"1234", "addr":"BeiJing" }, "john":{ "phone":"3456", "addr":"HeBei" }, "smith":{ "phone":"2504", "addr":"FuNan" } } #设置电话或地址的标签 labels = { "phone":"phone number", "addr":"address" } name = input("Name:") #查找电话还是地址,输入\'p\'或者\'a\' request = input("phone number(p) or address(a)?") #使用正确的键: if request == "p":key = "phone" if request == "a":key = "addr" #如果名字是字典中的有效键才打印信息: if name in people: print("%s\'s %s is %s."%(name,labels[key],people[name][key]))
4.2.3 字典的格式化字符串
在第3章,已经见过如何使用字符串格式化功能来格式化元组中的所有值。如果使用(只以字符串作为键的)字典而不是元组来做这个工作,会使字符串格式化更酷一些。在每个转换说明符中的%字符后面,加上(用圆括号括起来的)键,,后面跟上其他说明元素。
>>> phonebook = {"Alex":"2341","Bech":"9102","Cecil":"3158"} >>> "Cecil\'s phone number is %(Cecil)s." % phonebook "Cecil\'s phone number is 3158."
>>> template = \'\'\'<html> <head><title>%(title)s</title></head> <body> <h1>%(title)s</h1> <p>%(text)s</p> </body>\'\'\' >>> 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>
4.2.4 字典方法
字典的方法有:
1.clear
clear方法清除字典中所有的项。无返回值(或者返回None)。
>>> d = {} >>> d["name"] = "alex" >>> d["age"] = 23 >>> d {\'name\': \'alex\', \'age\': 23} >>> returned_values = d.clear() >>> d {} >>> print(returned_values) None
考虑一下两种情况。下面是第一种
>>> x = {} >>> y = x >>> x["key"] = "values" >>> x {\'key\': \'values\'} >>> x = {} >>> y {\'key\': \'values\'} >>>
然后是第2种情况:
>>> x = {} >>> y = x >>> x["key"] = "values" {\'key\': \'values\'} >>> x.clear() >>> y {} >>>
两种情况中,x和y最初对应同一个字典。情况1中,通过将x关联到一个新的空字典来"清空"它,这对y一点影响也没有,它还关联到原先的字典。这可能是所需要的行为,但是如果真的想清空原始字典中所有的元素,必须使用clear方法。正如情况2所示,y随后也被清空了。
2.copy
copy方法返回一个具有相同键-值对的新字典(这个方法实现的是浅复制(shallow copy),因为值本身就是相同的,而不是副本)。
>>> x = {"username":"admin","machines":["foo","bar","baz"]} >>> y = x.copy() >>> y {\'machines\': [\'foo\', \'bar\', \'baz\'], \'username\': \'admin\'} >>> y["username"] = "mth" >>> y["machines"].remove("bar") >>> y {\'machines\': [\'foo\', \'baz\'], \'username\': \'mth\'} >>> x {\'machines\': [\'foo\', \'baz\'], \'username\': \'admin\'}
可以看到,当在副本中替换值的时候,原始字典不受影响,但是,如果修改了某个值(原地修改,而不是替换),原始的字典也会改变,因为同样的值也存储在原字典中。为避免这个问题的一种方法就是使用深复制(deep copy),复制其包含所有的值。可以使用copy模块的deepcopy函数来完成操作:
>>> from copy import deepcopy >>> d = {} >>> d["names"] = ["alex","john"] >>> c = d.copy() >>> dc = deepcopy(d) >>> d["names"].append("tenglan") >>> c {\'names\': [\'alex\', \'john\', \'tenglan\']} >>> dc {\'names\': [\'alex\', \'john\']}
3.fromkeys
fromkeys方法适用给定的键建立新的字典,每个键默认对应的值为None。
>>> {}.fromkeys(["name","age"]) {\'name\': None, \'age\': None} >>>
>>> dict.fromkeys(["name","age"])
{\'name\': None, \'age\': None}
>>>
第一个例子是先构造了一个空字典,然后调用它的fromkeys方法,建立另外一个字典。也可以直接在所有字典的类型dict上面调用方法。如果不想使用None作为默认值,也可以自己提供默认值。
>>> dict.fromkeys(["name","age"],"unknown") {\'name\': \'unknown\', \'age\': \'unknown\'} >>>
4.get
get方法是个更宽松的访问字典项的方法。一般如果试图访问字典中不存在的项时会出错:
>>> d = {} >>> print (d["name"]) Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: \'name\'
而用get就不会:
>>> print (d.get("name")) None >>>
当使用get访问一个不存在的键时,没有任何异常,而得到了None值。自己也可以定"默认"值,替换None:
>>> d.get("name","N/A") \'N/A\'
如果键值存在,get就和普通的字典查询一样:
>>> d["name"] = "alex" >>> d.get("name") \'alex\'
下面代码演示使用get访问的示例,是4-1程序的修改版本。
#简单的名称、电话、地址数据库,根据输入的人名,查找对应的电话号码或者地址 people = { "alex":{ "phone":"1234", "addr":"BeiJing" }, "john":{ "phone":"3456", "addr":"HeBei" }, "smith":{ "phone":"2504", "addr":"FuNan" } } #设置电话或地址的标签 labels = { "phone":"phone number", "addr":"address" } name = input("Name:") #查找电话还是地址 request = input("phone number(p) or address(a)?") #关联用户的输入到相应的标签上,如果输入的信息不是p或者a key = request 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\'s %s is %s."%(name,label,result)) 输出结果: Name:Gumby phone number(p) or address(a)?weigth Gumby\'s weigth is not available.
6.items
items方法将所有的字典项以列表方式返回,这些列表项中的每一项都来自于(键,值)。
>>> d = {"title":"Python Web Site","url":"www.python.org","spam":0} dict_items([(\'url\', \'www.python.org\'), (\'title\', \'Python Web Site\'), (\'spam\', 0)])
7.keys
keys方法将字典中的键以列表形式返回。
>>> info = {\'stu1102\': \'LongZe Luola\', \'stu1103\': \'XiaoZe Maliya\'} >>> info.keys() dict_keys([\'stu1102\', \'stu1103\'])
8.values
values方法以列表的形式返回字典中的值。
>>> info = {\'stu1102\': \'LongZe Luola\', \'stu1103\': \'XiaoZe Maliya\'} >>> info.values() dict_values([\'LongZe Luola\', \'XiaoZe Maliya\'])
9.pop
pop方法用来去除指定的键值。
>>> info = {\'stu1102\': \'LongZe Luola\', \'stu1103\': \'XiaoZe Maliya\'} >>> info.pop("stu1102") >>> info {\'stu1103\': \'XiaoZe Maliya\'}
10.popitem
随机移除字典中的项
11.setdefault
setdefault方法在某种程度上类似于get方法,就是能够获得与给定键相关的值,除此之外,setdefault还能在字典中不含有给定键的情况下设定相应的键值。
>>> d = {} >>> d.setdefault("name","N/A") #当键值不存在,更新字典 \'N/A\' >>> d {\'name\': \'N/A\'} >>> d["name"] = "Gumby" >>> d.setdefault("name","N/A") #当键值存在,返回对应的值 \'Gumby\' >>> d {\'name\': \'Gumby\'}
当键不存在的时候,setdefault返回默认值并相应的更新字典,如果键存在,就返回与其对应的值,但不改变字典。如果不设定,默认值是None。
12.update
update方法可以利用一个字典项更新另外一个字典:
>>> d = {"title":"Python Web Site","url":"http://www.python.org"} >>> x = {"title":"Python Language Website","changed":"Mar 14 22:02:15 MET 2016"} >>> d.update(x) >>> d {\'url\': \'http://www.python.org\', \'title\': \'Python Language Website\', \'changed\':\'Mar 14 22:02:15 MET 2016\'}
新字典中的项会被添加到旧的字典中,若有相同的键则会进行覆盖。
4.3 小结
本章主要有以下内容:
映射:映射可以使用任何不可变对象标识元素。最常用的类型是字符串和元组。Python唯一内建的映射类型是字典。
利用字典格式化字符串:可以通过在格式化说明符中包括名称(键)来对字典应用字符串格式化操作。当在字符格式化中使用元组时,还需要对元组中一个元素都设定"格式化说明符"。
字典的方法:update,values,key,pop等
4.3.1 本章的新函数
新函数如表4-1所示。
以上是关于第4章 字典:当索引不好用时的主要内容,如果未能解决你的问题,请参考以下文章