在我们使用 Python 处理数据时,字典是最常用的数据结构。它易于使用,用途广泛。
比如需要计算字符串中某些字符出现次数?可以使用字典!
再比如统计一份足球运动员个人信息的相关数据?可以使用字典!
不过,字典也并非完美。在许多时候,当我们尝试通过键获取数据时会遇到大量 KeyErrors 错误,处理起来也是一件令人沮丧的事情。
处理这些错误需要额外编写代码。这不仅降低了可读性,还增加了复杂性。如果要处理的数据量过大,这个问题可能会失控。
collections 模块可以帮助我们很好的解决这个问题。collections 模块是 Python 标准库的一部分,它提供了一些非常实用的容器类型,可以帮助我们更方便地处理特定需求。
今天我们将探讨的是 defaultdict,要充分理解这个数据容器,你应该对 Python 普通字典类型有一定的了解。
使用 DefaultDict 简化代码
在进入今天的主题之前,我们先来看一种情况。我想创建一个字典,统计 “Mississippi” 这个单词中所有字母的个数。
下面是我使用标准字典的实现方法:
letters = {}
for letter in "Mississippi":
if letter not in letters:
letters[letter] = 1
else:
letters[letter] +=1
print(letters)
# {'M': 1, 'i': 4, 's': 4, 'p': 2}
很简单。这个程序
- 遍历字符串。
- 每次迭代时,检查字典中是否有该字母的条目。
- 如果存在,则在当前值的基础上加一。
- 如果不存在,则创建新条目并将初始值设置为一。
这个例子非常简单,但使用 defaultdict 仍然有改进余地。让我们看看该如何做:
from collections import defaultdict
letters = defaultdict(int)
for letter in "Mississippi":
letters[letter] += 1
print(letters)
# defaultdict(<class 'int'>, {'M': 1, 'i': 4, 's': 4, 'p': 2})
仔细观察以上代码,你应该能够注意到,现在所有的条件语句都不见了。代码变的更容易阅读了,但我们的程序仍然得到了相同的结果。
这就是 defaultdict 的好处,接下来让我们更进一步分析这个数据容器。
探索 DefaultDict 数据容器
其实 defaultdict 的工作原理很简单:如果试图访问或更改一个不存在的键,它就会创建一个具有给定默认值的新条目。
在上面的示例中,我们首先创建了一个没有任何条目的空 defaultdict。对于每一个字母,defaultdict 都会创建一个条目。由于我们使用 int 作为默认值生成器,因此新条目的初始值为 0。
在 DefaultDict 中设置默认值
当你创建 defaultdict 的实例时,需要将一个无参数的函数(或可调用对象)作为 default_factory 参数传递给 defaultdict 的构造函数。当你尝试访问不存在的键时,defaultdict 会自动调用这个 default_factory 函数,并将返回值作为该键的默认值。
例如,我们可以使用内置函数 int() 来创建 defaultdict:
d1 = defaultdict(int)
当试图访问一个不存在的条目时,它会调用 int() 函数,并将其返回值作为新条目的初始值,即 0。
d1 = defaultdict(int)
d1[“Adding an entry!”]
Print(d1)# defaultdict(<class 'int'>, {'Adding an Entry!': 0})
探索 DefaultDict 的更多使用技巧
现在我们已经知道了 defaultdict 的基本用法,让我们探索其更多使用技巧吧。
让我们回到前面的例子。我想知道所有字母所在位置的索引,该如何做?我们可以使用内置函数 list() 作为 default_factory 参数创建 defaultdict 实例,这样我们就可以记录所有索引了。
from collections import defaultdict
my_word = "Mississippi"
d1 = defaultdict(list)
for index, letter in enumerate(my_word):
d1[letter].append(index)
print(d1)
# defaultdict(<class 'list'>, {'M': [0], 'i': [1, 4, 7, 10], 's': [2, 3, 5, 6], 'p': [8, 9]})
这个例子看起来有点不同,但思路仍然相同。步骤如下
- 首先创建一个
defaultdict实例,使用内置函数list()作为default_factory参数。 - 迭代字符串 "Mississippi"。
- 如果字母对应的条目不存在,
defaultdict将会使用空列表作为初始值创建它。 - 最后,使用 append 方法将索引添加到字母对应条目列表中。
如前所述,default_factory 是一个不带参数的函数,这意味着我们不仅可以使用内置函数,还可以使用自定义函数,只要我们的自定义函数不包含参数即可。
from collections import defaultdict
def return_hello():
return "Hello!"
d1 = defaultdict(return_hello)
d1[1]
d1[2]
d1[3]
print(d1)
# defaultdict(<function return_hello at 0x0000014FC5D28DC0>, {1: 'Hello!', 2: 'Hello!', 3: 'Hello!'})
以上代码定义了一个返回 “Hello!” 字符串的简单函数,并将其作为 default_factory 参数创建一个 defaultdict 实例。当我们尝试访问其不存在的条目时,defaultdict 将会调用我们的自定义函数来生成默认值。
结语
在本教程中,我们介绍了 defaultdict,它是 Python 标准库 collections 模块中的一个数据容器,它提供了一个具有默认值的字典。
defaultdict 接受一个 default_factory 参数,该参数为字典中不存在的键提供一个默认值的生成器。default_factory 参数可以是内置函数,如 int 或 list,也可以是自定义函数,如上面的 return_hello 函数。