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

字典类型是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']}

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

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

(六)备忘录

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

可以看出,当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,它可以用一种更加人类可读的方式战术内建类型

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值