欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Think Python】Python笔记(十一)字典

程序员文章站 2022-04-25 20:21:17
...

字典类型是Python的一种内建数据类型;

(一)字典即映射

  • 字典实际上是与列表类似的,但是更加通用;
  • 列表中,索引必须是整数;但是在字典中,可以几乎可以是任何类型;
  • 字典包含一个索引的集合,称之为键(keys),还有一个**值(values)**的集合,一个键对应一个值,这种对应的关系称之为键值对,或者项;
  • dict函数生成一个不含任何项的新的字典,它是一个内建函数名,所以自定义函数的时候需要避免 与之重名;
>>> eng2sp = dict()
>>> eng2sp
{}
  • 花括号{}表示一个空的字典,可以使用方括号向其中增加项:
>>> eng2sp['one'] = 'uno'
>>> eng2sp
{'one', 'uno'}
  • 通常来说,字典中的键值对的顺序是不可预知的,但是键值对的映射关系是确定的:
>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}
>>> eng2sp
{'one': 'uno', 'three': 'tres', 'two': 'dos'}
  • len()函数也可以用于字典类型,求出字典中键值对的数量;
  • in操作符也适用于字典类型 ;可以用来检验字典中是不是存在某个键【不是值】
>>> 'one' in eng2sp
True
>>> 'uno' in eng2sp
False
  • 想要知道字典中是不是存在某个值,可以使用values方法,这个方法返回值的集合,然后使用in操作符进行验证:
>>> vals = eng2sp.values()
>>> 'uno' in vals
True
  • in操作符对列表和字典采用不同的算法:
    • 对于列表,使用的是顺序查找;
    • 对于字典,使用的是哈希表的算法;这样无论字典中含有多少项,in操作符搜索的时间是一样的;

(二)字典作为计数器集合

  • 给定一个字符串,计算每个字母出现的次数:
def  histogram(s):
    d = dict()
    for c in s:
        if c in d:
            d[c] += 1
        else:
            d[c] = 1
    return d
>>> h = histogram('brontosaurus')
>>> h
{'a': 1, 'b': 1, 'o': 2, 'n': 1, 's': 2, 'r': 2, 'u': 2, 't': 1}
  • 字典类有一个get方法,接受一个键和一个默认值作为参数:如果字典中存在该键,则返回对应值;否则返回传入的默认值
>>> h = histogram('a')
>>> h
{'a' : 1}
>>> h.get('a', 0)
1
>>> h.get('b', 0)
0

(三)循环和字典

for循环中使用字典会遍历其所有的键:

def print_hist(h):
    for c in h:
        print(c, h[c])

>>> h = histogram('parrot')
>>> print_hist(h)
a 1
p 1
r 2
t 1
o 1
  • 字典中的键是无序的,如果想要按照顺序遍历字典,使用内建方法sorted
>>> for key in sorted(h)
...		print(key, h[key])
a 1
o 1
p 1
r 2
t 1

(四)逆向查找

  • 给定一个字典d和一个键t,很容易找到相对应的值v = d[t],这个过程称之为查找;
  • 但是如果想通过值v,查找相对应的键key;这个过程是比较麻烦的,因为:第一,可能有多于一个的键对应同样的值;第二,没有简单的语法可以完成这个过程,必须进行搜索;
  • 下面的函数接受一个值,并返回映射到这个值的第一个键:
def reverse_lookup(d, v):
    for k in d:
        if d[k] == v:
            return k
    raise LookupError
  • 这里raise语句可以触发异常,这里是触发了LookupError,这是一个表示查找操作失败的内建异常;

    • 成功的逆向查找的例子:
    >>> h = histogram('parrot')
    >>> key = reverse_lookup(h, 2)
    >>> key
    'r'
    
    • 失败的例子:
    >>> key = reverse_lookup(h, 3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in reverse_lookup
    LookupError
    
  • raise语句接受一个详细的错误信息作为可选的参数:

raise LookupError('value does not appear in the dictionary')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
LookupError: value does not appear in the dictionary

(五)字典和列表

在字典中,列表可以作为值出现;

  • 下面的函数实现倒转字典:
def invert_dict(d):
    inverse = dict()
    for key in d:
        val = d[key]
        if val not in inverse:
            inverse[val] = [key]
        else:
            inverse[val].append(key)
  • 例子:
>>> hist = histogram('parrot')
>>> hist
{'a': 1, 'p': 1, 'r': 2, 't': 1, 'o': 1}
>>> inverse = invert_dict(hist)
>>> inverse
{1: ['a', 'p', 't', 'o'], 2: ['r']}

【Think Python】Python笔记(十一)字典

  • 列表可以作为字典的值,但是不能作为键;因为字典使用哈希表实现,这意味着键必须是可哈希的(hashable)

  • 类似的,一些可变类型都不可以作为字典的键;不能使用数组作为键,但是可以使用元组;

(六)备忘录

  • fibonacci函数中,输入的参数越大,函数运行的时间越长,而且时间增长的非常快,原因如下:

【Think Python】Python笔记(十一)字典

可以看出,当n=1和n=0被重复调用的很多次,而且随着参数的不断变大,这种冗余会越来越大;

  • 一个解决的办法是将已经计算的值保存在字典中,这个称之为备忘录(memo),如下:
known = {0:0, 1:1}

def fibinacci(n):
    if n in known:
        return known[n]
    
    res = fibonacci[n-1] + fibonacci[n-2]
    known[n] = res
    return res

(七)全局变量

  • 上面的例子中,known是在函数的外部创建的,所以它属于被称之为__main__的特殊帧;
  • __main__中的变量可以被任何函数进行访问,所以称之为全局变量(global)
  • 函数中的变量会随着函数的结束而消失,但是全局变量在不同函数调用时一直存在;
  • 全局变量经常用作标记(flag),也就是说明(标记)一个条件是否为真的布尔变量
  • 在函数内部对全局变量重新赋值,必须声明这个 是全局变量:
been_called = False

def example():
    global been_called
    been_called = True
  • 如果全局变量是可变的,可以不加声明地修改:
known = {0:0, 1:1}

def example():
    know[2] = 1
  • 但是,如果想要对变量重新进行赋值,必须声明:
def example():
    global known
    known = doct()

全局变量有时是很有用的,但如果你的程序中有很多全局变量,而且修改频繁, 这样会增加程序调试的难度。

(八)调试

当使用较大的数据集的时候,通过打印并手工检查数据进行调试是很不方便的

  • 针对这个问题的建议:

    • 缩小输入:如果有可能,减小数据集合的大小;如果出错了,你可以将 n 缩小为会导致该错误的最小值,然后在查找和解决错误的同时,逐步增加 n 的值。

    • 检查摘要和类型:考虑打印数据的摘要,而不是打印并检查全部的数据集合;运行时错误一个常见原因是数据类型不正确

    • 编写自检代码:有时候可以写代码自动检查错误:

      • 例如,如果你正在计算数字列表的平均数,你可以检查其结果是不是大于列表中最大的元素,或者小于最小的元素。 这被称 作“合理性检查”,因为它能检测出“不合理的”结果。
      • 另一类检查是比较两个不同计算的结果,来看一下它们是否一致。这被称作“一致性检查”。
    • 格式化输出:在第六节的调试中;还有一个是pprint,它可以用一种更加人类可读的方式战术内建类型

    • 在编程的时候,搭建一些脚手架代码,可以有效减少调试的时间;

相关标签: Python