Python字典常用操作小技巧¶
Info
作者:Vincent,发布于2021-08-21,阅读时间:约6分钟,微信公众号文章链接:
1 前言¶
在上一篇文章中,我们回顾了Python列表的常用操作,列表作为一种常用的数据类型在日常工作中扮演了非常重要的作用,这篇文章我们继续聊聊Python里另一种常用的数据类型 - 字典(Dict)。
定义字典可以使用dict()
方法,或者使用花括号name2code = {'Tony':1, 'Kevin':2, 'Luis':3}
,如果想要增加元素,可以使用键值对的赋值模式:name2code['Nick'] = 0
。很容易看出,不同于列表,字典并不以整数作为下标。接下来我们来看看字典常用的方法。
2 字典常用方法¶
2.1 索引¶
字典以键值对的形式出现,因此可以用键来索引所需要的值,如:
print(name2code['Nick'] )
输出为:
0
类似于列表,可以使用in
操作符查看字典中是否含有所要查找的键,值得注意的是,in
操作符在列表和字典中的实现有所区别,列表使用搜索算法,因此列表变长时,搜索时间也会变长,但是字典使用散列表(hashtable)的算法,因此不论字典中有多少键值对,in
操作符所花时间都差不多。
print('Nick' in name2code)
输出为:
True
如果要查看值是否在字典中,可以借助values()
方法取出字典的值,然后用in操作符查看:
values = name2code.values()
print(0 in values)
输出为:
True
2.2 删除元素¶
字典删除元素的方法与列表类似:
- 清空字典:
name2code.clear()
,注意clear()
方法没有返回值 - 返回键k对应的值,然后移除该键值对:
name2code.pop(k, [default])
- 返回最后添加的键值,并移除该键值对:
name2code.popitem()
2.3 循环¶
使用for循环可以遍历字典的键,请注意,因为键可散列,所以其出现不遵循特定的顺序,以下代码在你的电脑上运行可能会有不同的输出顺序(注:Python 3.6及之后的版本保留了键值对添加的顺序,所以结果是确定的了):
for i in name2code:
print(i, name2code[i])
输出为:
Tony 1
Kevin 2
Luis 3
Nick 0
如果同时想用键和值进行遍历,也可使用items()
方法:
for k,v in name2code.items():
print(k,v)
输出为:
Tony 1
Kevin 2
Luis 3
Nick 0
2.4 反向查找¶
对于一个字典,使用键去找值的操作在上文已做介绍,如果想用值来寻找键,此时应做反向查找的操作,注意这里使用了一个raise语句
抛出异常,用于显示参数的值有问题。
def reversed_lookup(d,v):
for i in d:
if d[i] == v:
return i
raise ValueError("所查找的值不在字典中")
reversed_lookup(name2code,5)
输出为:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-33-832e824fe6b4> in <module>
----> 1 reversed_lookup(name2code,5)
<ipython-input-32-be75152f6e58> in reversed_lookup(d, v)
4 return i
5
----> 6 raise ValueError("所查找的值不在字典中")
ValueError: 所查找的值不在字典中
2.5 字典推导¶
从Python 2.7开始,列表推导和生成器表达式也被移植到了字典上,示例如下,
code2name = {code:name for name,code in name2code.items() if code < 2}
print(code2name)
输出为:
{1: 'Tony', 0: 'Nick'}
3 字典的变种¶
除了dict之外,在Python标准库里collections模块中还有若干种不同的映射类型:
- collections.OrderedDict:这个类型在添加键的时候会保持键的顺序,因此键的迭代顺序始终保持一致。但请注意,如果定义完有序字典后没有插入数据的操作,原始的键值对仍然是无序的,和普通字典一样。
- collections.ChainMap:这个类型可以容纳多个不同的映射对象,在进行键查找操作时,这些对象会被逐个查找,直到找到对应的键为止。常用于管理多个代表不同范围和上下文的字典。
- collections.Counter:顾名思义,这是一个计数器,键更新时,计数器也随之更新。常用于为可散列表计数或作为多重集合(集合里元素出现多次)。
- colllections.UserDict:该类主要用于让用户继承,继承这个类会比继承dict要更加方便,主要是因为dict等内置类型的方法通常会忽略用户覆盖的方法,造成意料不到的麻烦,详见《流畅的Python》 12章 - 继承的优缺点。
4 总结¶
上述知识点在日常工作中都十分常用,以下内容还涵盖了许多Python程序员多年实践经验的总结,让我们再回顾一下:
- dict的键必须是可散列的。意味着在这个对象的生命周期中散列值不变,并且对象要实现
__hash__
方法,支持通过使用__eq__
方法验证相等性。 - dict内存耗费巨大。因为字典使用散列表,散列表又必须稀疏,导致空间利用率低下。如果数据量巨大,建议使用元组或者列表。
- 键查询效率很高。只要字典能被装进内存,其键查询速度不随数据量增大而减缓,但速度快的代价是较大的空间使用。
- 向dict里添加新的键可能会改变已有键的顺序。具体原因与dict实现方式有关,建议不要对dict同时进行迭代和修改,最好分成两步:先迭代找到需要修改的内容并记录下来,迭代之后再对原dict更改。
在回顾这些知识时,自己也有了新的理解和收获,希望这些内容也对你有帮助!