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