Now I appeal to you, brothers and sisters, by the name of our Lord Jesus Christ, that all of you be in agreement and that there be no divisions among you, but that you be united in the same mind and the same purpose. (1 CORINTHIANS 1:10)

字典(1)

字典,这个东西你现在还用吗?随着网络的发展,用的人越来越少了。不少人习惯于在网上搜索,不仅有web版,乃至于已经有手机版的各种字典了。

我曾经上过小学,这是事实,那时候曾经用过一本小小的《新华字典》,与我差不多年龄的朋友,也都有同样的记忆,没记错的话应该是1.01元人民币一本。

《新华字典》是中国第一部现代汉语字典。最早的名字叫《伍记小字典》,但未能编纂完成。自1953年,开始重编,其凡例完全采用《伍记小字典》。从1953年开始出版,经过反复修订,但是以1957年商务印书馆出版的《新华字典》作为第一版。原由新华辞书社编写,1956年并入中科院语言研究所(现中国社科院语言研究所)词典编辑室。新华字典由商务印书馆出版。历经几代上百名专家学者10余次大规模的修订,重印200多次。成为迄今为止世界出版史上最高发行量的字典。

这里讲到字典,不是为了回忆青葱岁月。而是提醒读者想想曾经如何使用字典:先查索引(不管是拼音还是偏旁查字),然后通过索引找到相应内容。不用从头开始一页一页地找。

这种方法能够快捷的找到目标。

正是基于这种需要,Python中有了一种叫做dictionary的对象(数据)类型,翻译过来就是“字典”,用dict表示。

假设一种需要,要存储城市和电话区号,苏州的区号是0512,唐山的是0315,北京的是011,上海的是012。用前面已经学习过的知识,可以这么来做:

>>> citys = ["suzhou", "tangshan", "beijing", "shanghai"]
>>> city_codes = ["0512", "0315", "011", "012"]

用一个列表来存储城市名称,然后用另外一个列表,一一对应地保存区号。假如要输出苏州的区号,可以这么做:

>>> print "{} : {}".format(citys[0], city_codes[0])
suzhou : 0512

请特别注意,我在city_codes中,表示区号的元素没有用整数型,而是使用了字符串类型,你知道为什么吗?

如果用整数,就是这样的。

>>> suzhou_code = 0512
>>> print suzhou_code
330

怎么会这样?!读者能不能给出解答?

这样来看,用两个列表分别来存储城市和区号,似乎能够解决问题。但是,这不是最好的选择,至少在Python里面。因为Python还提供了另外一种方案,那就是字典(dict)。

创建字典

创建字典,有多种方法,依次尝试。

方法1:

创建一个空的字典,然后可以向里面加东西。

>>> mydict = {}
>>> mydict
{}

不要小看“空”,“色即是空,空即是色”,在编程中,“空”是很重要。一般带“空”字的人都很有名,比如孙悟空,哦。好像他应该是猴、或者是神。举一个人的名字,带“空”字,你懂得。

还可以创建不空的字典。

>>> person = {"name":"qiwsir", "site":"qiwsir.github.io", "language":"python"}
>>> person
{'name': 'qiwsir', 'language': 'python', 'site': 'qiwsir.github.io'}

"name":"qiwsir",有一个优雅的名字:键/值对。前面的name叫做键(key),后面的qiwsir是前面的键所对应的值(value)。

在一个字典中,键是唯一的,不能重复。值则是对应于键,值可以重复。

键值之间用(:)英文的冒号,每一对键值之间用英文的逗号(,)隔开。

向已经建立的字典中,增加键值对的一种方法是这样的:

>>> person['name2'] = "qiwsir"
>>> person
{'name2': 'qiwsir', 'name': 'qiwsir', 'language': 'python', 'site': 'qiwsir.github.io'}

用这样的方法可以向一个字典类型的对象中增加“键值对”,也可以说是增加数值。那么,增加了值之后,那个字典还是原来的吗?也就是也要同样探讨一下,字典是否能原地修改?(列表可以,所以列表是可变的;字符串和元组都不行,所以它们是不可变的。)

>>> ad = {}
>>> id(ad)
3072770636L
>>> ad["name"] = "qiwsir"
>>> ad
{'name': 'qiwsir'}
>>> id(ad)
3072770636L

实验表明,字典可以原地修改,即它是可变的。

方法2:

利用元组建构字典,方法如下:

>>> name = (["first", "Google"], ["second", "Yahoo"])      
>>> website = dict(name)
>>> website
{'second': 'Yahoo', 'first': 'Google'}

或者用这样的方法:

>>> ad = dict(name = "qiwsir", age = 42)
>>> ad
{'age': 42, 'name': 'qiwsir'}

方法3:

这个方法,跟上面的不同在于使用fromkeys

>>> website = {}.fromkeys(("third", "forth"), "facebook")
>>> website
{'forth': 'facebook', 'third': 'facebook'}

需要提醒注意的是,在字典中的“键”,必须是不可变的数据类型;“值”可以是任意数据类型。

>>> dd = {(1,2):1}
>>> dd
{(1, 2): 1}
>>> dd = {[1,2]:1}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

访问字典的值

字典对象是以键值对的形式存储数据的,所以,只要知道键,就能得到值。这本质上就是一种映射关系。

映射,就好比“物体”和“影子”的关系,“形影相吊”,两者之间是映射关系。此外,映射也是一个严格数学概念:A是非空集合,A到B的映射是指:A中每个元素都对应到B中的某个元素。

既然是映射,就可以通过字典的“键”找到相应的“值”。

>>> person = {'name2': 'qiwsir', 'name': 'qiwsir', 'language': 'python', 'site': 'qiwsir.github.io'}
>>> person['name']
'qiwsir'
>>> person['language']
'python'

通过“键”能够读取到相应的“值”。在前面的操作中,也显示了,通过“键”能够增加字典中的“值”。

还有,通过“键”能够改变字典中的“值”。

本节开头那个城市和区号的关系,也可以用字典来存储和读取。

>>> city_code = {"suzhou":"0512", "tangshan":"0315", "beijing":"011", "shanghai":"012"}
>>> print city_code["suzhou"]
0512

既然字典是键值对的映射,就不用考虑所谓“排序”问题了,只要通过键就能找到值,至于这个键值对位置在哪里就不用考虑了。比如,刚才建立的city_code

>>> city_code
{'suzhou': '0512', 'beijing': '011', 'shanghai': '012', 'tangshan': '0315'}

虽然这里显示的和刚刚赋值的时候顺序有别,但是不影响读取其中的值。

在列表中,得到值是用索引的方法。那么在字典中有索引吗?当然没有,因为它没有顺序,哪里来的索引呢?所以,在字典中就不要什么索引和切片了。

字典中的这类以键值对的映射方式存储数据,是一种非常高效的方法,比如要读取值得时候,如果用列表,Python需要从头开始读,直到找到指定的那个索引值。但是,在字典中是通过“键”来得到值。要高效得多。 正是这个特点,键值对这样的形式可以用来存储大规模的数据,因为检索快捷。规模越大越明显。所以,mongdb这种非关系型数据库在大数据方面比较流行了。

基本操作

字典虽然跟列表有很大的区别,但是依然有不少类似的地方。它的基本操作:

  • len(d),返回字典(d)中的键值对的数量
  • d[key],返回字典(d)中的键(key)的值
  • d[key]=value,将值(value)赋给字典(d)中的键(key)
  • del d[key],删除字典(d)的键(key)项(将该键值对删除)
  • key in d,检查字典(d)中是否含有键为key的项

依次进行演示。

>>> city_code
{'suzhou': '0512', 'beijing': '011', 'shanghai': '012', 'tangshan': '0315'}
>>> len(city_code)
4

以city_code为操作对象,len(city_code)的值是4,表明有四组键值对,也可以说是四项。

>>> city_code["nanjing"] = "025"
>>> city_code
{'suzhou': '0512', 'beijing': '011', 'shanghai': '012', 'tangshan': '0315', 'nanjing': '025'}

向其中增加一项

>>> city_code["beijing"] = "010"
>>> city_code
{'suzhou': '0512', 'beijing': '010', 'shanghai': '012', 'tangshan': '0315', 'nanjing': '025'}

突然发现北京的区号写错了。可以这样修改。这进一步说明字典的值是可变的。

>>> city_code["shanghai"]
'012'
>>> del city_code["shanghai"]

通过city_code["shanghai"]能够查看到该键(key)所对应的值(value),结果发现也错了。干脆删除,用del,将那一项都删掉。

>>> city_code["shanghai"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'shanghai'
>>> "shanghai" in city_code
False

因为键是"shanghai"的那个键值对项已经删除了,随意不能找到,用in来看看,返回的是False

>>> city_code
{'suzhou': '0512', 'beijing': '010', 'tangshan': '0315', 'nanjing': '025'}

真的删除了哦。没有了。

字符串格式化输出

这是一个前面已经探讨过的话题,请参看《字符串(4)》,这里再次提到,就是因为用字典也可以实现格式化字符串的目的。

>>> city_code = {"suzhou":"0512", "tangshan":"0315", "hangzhou":"0571"}
>>> " Suzhou is a beautiful city, its area code is %(suzhou)s" % city_code
' Suzhou is a beautiful city, its area code is 0512'

这种写法是非常简洁,而且很有意思的。有人说它简直是酷。

其实,更酷还是下面的——模板

在做网页开发的时候,通常要用到模板,也就是你只需要写好HTML代码,然后将某些部位空出来,等着Python后台提供相应的数据即可。

当然,下面所演示的是玩具代码,基本没有什么使用价值,因为在真实的网站开发中,这样的姿势很少用上。但是,它绝非花拳绣腿,而是你能够明了其本质,至少了解到一种格式化方法的应用。

>>> temp = "<html><head><title>%(lang)s<title><body><p>My name is %(name)s.</p></body></head></html>"
>>> my = {"name":"qiwsir", "lang":"python"}
>>> temp % my
'<html><head><title>python<title><body><p>My name is qiwsir.</p></body></head></html>'

temp就是所谓的模板,在双引号所包裹的实质上是一段HTML代码。然后在字典中写好一些数据,按照模板的要求在相应位置显示对应的数据。

是不是一个很有意思的屠龙之技?

什么是HTML? 下面是在《维基百科》上抄录的:

超文本标记语言(英文:HyperText Markup Language,HTML)是为「网页创建和其它可在网页浏览器中看到的信息」设计的一种标记语言。HTML被用来结构化信息——例如标题、段落和列表等等,也可用来在一定程度上描述文档的外观和语义。1982年由蒂姆·伯纳斯-李创建,由IETF用简化的SGML(标准通用标记语言)语法进行进一步发展的HTML,后来成为国际标准,由万维网联盟(W3C)维护。

HTML经过发展,现在已经到HTML5了。现在的HTML设计,更强调“响应式”设计,就是能够兼顾PC、手机和各种PAD的不同尺寸的显示器浏览。如果要开发一个网站,一定要做到“响应式”设计,否则就只能在PC上看,在手机上看就不得不左右移动。

知识

什么是关联数组?以下解释来自维基百科

在计算机科学中,关联数组(英语:Associative Array),又称映射(Map)、字典(Dictionary)是一个抽象的数据结构,它包含着类似于(键,值)的有序对。一个关联数组中的有序对可以重复(如C++中的multimap)也可以不重复(如C++中的map)。

这种数据结构包含以下几种常见的操作:

1.向关联数组添加配对 2.从关联数组内删除配对 3.修改关联数组内的配对 4.根据已知的键寻找配对

字典问题是设计一种能够具备关联数组特性的数据结构。解决字典问题的常用方法,是利用散列表,但有些情况下,也可以直接使用有地址的数组,或二叉树,和其他结构。

许多程序设计语言内置基本的数据类型,提供对关联数组的支持。而Content-addressable memory则是硬件层面上实现对关联数组的支持。

什么是哈希表?关于哈希表的叙述比较多,这里仅仅截取了概念描述,更多的可以到维基百科上阅读

散列表(Hash table,也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构。也就是说,它通过把键值通过一个函数的计算,映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。

以上对字典有了基本了解,后面要深入对字典的认识。


总目录   |   上节:元组   |   下节:字典(2)

如果你认为有必要打赏我,请通过支付宝:[email protected],不胜感激。

results matching ""

    No results matching ""