Python学习笔记 - 8.字典(Dict)

时间:2022-05-25 05:35:00

与列表相比的特点:

列表中的索引位置必须是整数,而字典中索引几乎可以是任意类型

字典

字典可看作是索引(这里称为键)的集合值的集合之间存在的一种映射
每个键对应一个值,键与值之间的关系称之为键值对,有时也称为数据项
dict函数(内置函数)可以创建一个空字典。

    >>> eng2sp = dict()
>>> print eng2sp
{}

大括号{}表示一个空字典。你可以使用方括号向字典里添加数据项

    >>> eng2sp['one'] = 'uno'

这行语句创建了一个从键“one”到值“uno”映射的字典项。如果再次打印这个字典,我们会看到一个键值对,键与值之间用冒
号隔开。

    >>> print eng2sp
{'one': 'uno'}

字典的输入形式输出形式是一样的。举例来说,你可以创建一个包含三个数据项的字典:

    >>> eng2sp = {'one':    'uno',  'two':  'dos',  'three':    'tres'}

但是,如果你直接打印eng2sp,其结果会出人意料:

    >>> print eng2sp
{'one': 'uno', 'three': 'tres', 'two': 'dos'}

输出的键值对顺序发生了改变。一般而言,字典的顺序往往不可预测。
这个无所谓。因为字典项不是用整数来索引,而是采用来查找对应的值。

    >>> print eng2sp['two']
'dos'

键“two”对应的值是“dos”,这与字典项的顺序无关。
len函数也适用于字典,它会返回字典中键值对的个数。

    >>> len(eng2sp)
3

in操作符也适用于字典,它会告知你查找的东西是否作为存在于字典中,但不能对是否是值作出很好的判断。

    >>> 'one' in eng2sp
True
>>> 'uno' in eng2sp
False

为了判断要找的东西是否作为值存在于字典中,使用values方法,它会返回字典中所有值的一个列表,然后使用in操作符作
出判断。

    >>> vals = eng2sp.values()
>>> 'uno' in vals
True

字典作为计数器

字典实现的一个优点在于,我们不必事先知道字符串中出现了哪些字母,只需为确实会出现的字母分配空间就好了。

    word = 'brontosaurus'
d = dict()
for c in word:
if c not in d:
d[c] = 1
else:
d[c] = d[c] + 1
print d

每次循环时,如果字符c不在字典中,我们就创建一个字典项,以c为键,初始值1(表示这个字母至此出现了一次)。如果c已经存在于字典中,只需将对应值d[c]加1即可。

字典有一个get方法,该方法拥有一个键一个默认值。**如果键出现在字典中,那么它会返回此键对应的值。如果键不在字典
中,返回事先给定的默认值**。示例程序如下:

    >>> counts = {'chuck':1 ,'annie':42,'jan':100}
>>> print counts.get('jan', 0)
100
>>> print counts.get('tim', 0)
0

我们使用get方法可以把直方图循环写得更简洁。因为get方法自动处理了键不在字典中的情况。这样的话,代码的4条语句可
缩减至1条,还可以去掉if语句。

    word = 'brontosaurus'
d = dict()
for c in word:
d[c] = d.get(c,0) + 1
print d

使用get方法简化计数循环的做法已经成为Python中的一种普遍做法。

字典与文件

字典的常见用法之一是对书面文字的文本文件进行词频统计
编写一个Python程序,读取文件的每一行,并将每一行*分解为由单词组成的一个列表*。然后,遍历每个单词,使用字典来统计每个单词的出现次数。

    fname = raw_input('Enter    the file    name:   ')
try:
fhand = open(fname)
except:
print 'File cannot be opened:', fname
exit()
counts = dict()
for line in fhand:
words = line.split() #通过指定字符对字符串进行切片
for word in words:
if word not in counts:##这句话注意怎么写***
counts[word] = 1
else:
counts[word] += 1
print counts

split()方法 :通过指定字符对字符串进行切片

循环与字典

通过for语句循环读取每一个及其对应的:

    counts = {  'chuck':1, 'annie':42,'jan':100}
for key in counts:
print key,counts[key]

程序运行结果如下:

    jan 100
chuck 1
annie 42

如果按照字母顺序输出字典中的键,首先使用字典对象的keys方法,将所有的键放入一个列表。然后,对这个列表进行排
序,对排序后的列表进行迭代。依照字母顺序,通过每个键输出对应的键值对:

    counts = {'chuck':1,'annie':42,'jan':100}
lst = counts.keys()
print lst
lst.sort()
for key in lst:
print key,counts[key]

程序运行的输出结果如下:

    ['jan', 'chuck',    'annie']
annie 42
chuck 1
jan 100

首先,通过keys方法得到了包含键的未排序的列表。然后,通过for循环得到有序的键值对。

高级文本解析

实际的文本会包含大量标点符号:
通过字符串的lower(大小写转换)、punctuation(列出标点符号需要哪些字符)与translate(删除指定的所有字符)方法可以解决上述问题。其中translate是最精细的方法。

Translate方法使用:

    string.translate(s, table[, deletechars])

首先,从s中删除deletechars参数(如果存在的话)指定的所有字符,然后使用table参数来翻译字符。table是一个256个字
符长的字符串,用来翻译每个字符值,并按照序数进行索引。如果table是None值,只会执行字符删除步骤。
这里不指定table参数,用deletechars参数来删除所有标点符号。

Python甚至可以告诉我们,标点符号包括哪些字符:

    >>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

我们对程序做出如下修改:

    import string                                                                                                                                                                                                                                                                                                                                                                          
#New Code
fname = raw_input('Enter the file name:')
try:
fhand = open(fname)
except:
print 'File cannot be opened:',fname
exit()
counts = dict()
for line in fhand:
line = line.translate(None, string.punctuation)
#New Code 这行代码好好看看
line = line.lower()
#New Code
words = line.split()
for word in words:
if word not in counts:
counts[word] = 1
else:
counts[word] += 1
print counts

我们使用translate方法删除了所有的标点符号,并将每一行中的字母转换为小写。

查看这些输出仍然很费事,让Python来帮助我们找到具体要找到的信息。要做到这一点,我们需要学习Python的元组。

调试

编写自检程序:

有时通过编写代码来自动检查错误。例如,需要计算数字列表的平均数,你可以检查这个结果是不是处于列
表的最大值与最小值之间。这种检查称为“逻辑检查”,它会检测出哪些结果是完全不符合逻辑的。

一致性检查

比较两种不同计算的结果,检查它们是否一致。。

工整化输出结果:

对调试的输出结果进行格式化,这有助于发现错误。

再次强调,在程序架构上花些心思能有效减少调试的时间花费。