geekdoc-python-zh/docs/pythonlibrary/python-201-the-handy-defaul...

171 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# python 201——方便的默认字典
> 原文:<https://www.blog.pythonlibrary.org/2016/03/23/python-201-the-handy-defaultdict/>
collections 模块有另一个方便的工具叫做 **defaultdict** 。defaultdict 是 Python 的 dict 的子类,它接受 default_factory 作为其主要参数。default_factory 通常是 Python 类型,比如 int 或 list但是也可以使用函数或 lambda。让我们首先创建一个常规的 Python 字典,它计算每个单词在一个句子中的使用次数:
```py
sentence = "The red for jumped over the fence and ran to the zoo for food"
words = sentence.split(' ')
reg_dict = {}
for word in words:
if word in reg_dict:
reg_dict[word] += 1
else:
reg_dict[word] = 1
print(reg_dict)
```
如果运行此代码,您应该会看到类似于以下内容的输出:
```py
{'The': 1,
'and': 1,
'fence': 1,
'food': 1,
'for': 2,
'jumped': 1,
'over': 1,
'ran': 1,
'red': 1,
'the': 2,
'to': 1,
'zoo': 1}
```
现在让我们尝试用 defaultdict 做同样的事情!
```py
from collections import defaultdict
sentence = "The red for jumped over the fence and ran to the zoo for food"
words = sentence.split(' ')
d = defaultdict(int)
for word in words:
d[word] += 1
print(d)
```
您会马上注意到代码简单多了。defaultdict 会自动将零作为值赋给它还没有的任何键。我们增加一个,这样更有意义,如果这个词在句子中出现多次,它也会增加。
```py
defaultdict(,
{'The': 1,
'and': 1,
'fence': 1,
'food': 1,
'for': 2,
'jumped': 1,
'over': 1,
'ran': 1,
'red': 1,
'the': 2,
'to': 1,
'zoo': 1})
```
现在让我们尝试使用 Python 列表类型作为我们的默认工厂。像以前一样,我们先从一本普通的字典开始。
```py
my_list = [(1234, 100.23), (345, 10.45), (1234, 75.00),
(345, 222.66), (678, 300.25), (1234, 35.67)]
reg_dict = {}
for acct_num, value in my_list:
if acct_num in reg_dict:
reg_dict[acct_num].append(value)
else:
reg_dict[acct_num] = [value]
print(reg_dict)
```
这个例子基于我几年前写的一些代码。基本上我是一行一行地读一个文件,需要获取账号和支付金额,并跟踪它们。然后在最后,我会总结每个帐户。我们在这里跳过求和部分。如果您运行此代码,您应该会得到类似如下的输出:
```py
{345: [10.45, 222.66], 678: [300.25], 1234: [100.23, 75.0, 35.67]}
```
现在让我们使用 defaultdict 重新实现这段代码:
```py
from collections import defaultdict
my_list = [(1234, 100.23), (345, 10.45), (1234, 75.00),
(345, 222.66), (678, 300.25), (1234, 35.67)]
d = defaultdict(list)
for acct_num, value in my_list:
d[acct_num].append(value)
print(d)
```
这又一次去掉了 if/else 条件逻辑,使代码更容易理解。下面是上面代码的输出:
```py
defaultdict(,
{345: [10.45, 222.66],
678: [300.25],
1234: [100.23, 75.0, 35.67]})
```
这是一些很酷的东西!让我们继续尝试使用 lambda 作为我们的默认工厂!
```py
>>> from collections import defaultdict
>>> animal = defaultdict(lambda: "Monkey")
>>> animal['Sam'] = 'Tiger'
>>> print animal['Nick']
Monkey
>>> animal
defaultdict( at 0x7f32f26da8c0>, {'Nick': 'Monkey', 'Sam': 'Tiger'})
```
这里我们创建一个 defaultdict它将把“Monkey”作为默认值分配给任何键。第一个键我们设置为“Tiger”然后下一个键我们根本不设置。如果你打印第二个键你会看到它被赋值为“Monkey”。如果您还没有注意到只要您将 default_factory 设置为有意义的值,基本上不可能导致 **KeyError** 发生。文档中确实提到,如果您碰巧将 default_factory 设置为 **None** ,那么您将会收到一个 **KeyError** 。让我们看看它是如何工作的:
```py
>>> from collections import defaultdict
>>> x = defaultdict(None)
>>> x['Mike']
Traceback (most recent call last):
Python Shell, prompt 41, line 1
KeyError: 'Mike'
```
在这种情况下,我们只是创建了一个非常破的 defaultdict。它不能再为我们的键分配默认值所以它抛出一个 KeyError。当然由于它是 dict 的一个子类,我们只需将 key 设置为某个值就可以了。但是这有点违背了默认字典的目的。
* * *
### 包扎
现在,您已经知道如何使用 Python 集合模块中方便的 defaultdict 类型。除了刚才看到的赋值默认值之外,您还可以用它做更多的事情。我希望您能在自己的代码中找到一些有趣的用法。
* * *
### 相关阅读
* 默认字典[文档](https://docs.python.org/2/library/collections.html#collections.defaultdict)
* 本周 Python 模块- [defaultdict](https://pymotw.com/2/collections/defaultdict.html)
* 在 Python 中使用 default dict-[accele brate](https://www.accelebrate.com/blog/using-defaultdict-python/)