在Python中创建Defaultdict的Defaultdict
Python 有内置的容器,如 dict、list、set 和 tuple,它们有一个通用的思想体系。为了扩展或改进这些通用的容器,Python 提供了一个模块,引入了专门的容器数据类型,称为 Python Collections。
其中一个专门的容器数据类型是defaultdict
,它是默认的 Python 字典 (dict) 的一个很好的替代品 (和一个子类)。使用defaultdict
,你可以提供一个factory
函数来提供缺失的值 (而不是一个KeyError
异常或消息)。
因此,如果键在字典中不存在,factory
函数被调用并返回一个值,而不是引发一个KeyError
异常。
使用defaultdict
可能相对简单,但使用defaultdict
的defaultdict
可能会令人困惑。本文将解释如何在不引起任何错误的情况下创建defaultdict
的defaultdict
,以及它的内在操作是如何发生的。
使用lambda
在 Python 中创建 Defaultdict 的 Defaultdict
为了利用Python集合和固有的defaultdict
,你可以使用Python表达式导入collection
模块:
from collections import defaultdict
注意defaultdict
是dict
类的一个子类,下面的Python表达式可以检查这个子类:
issubclass(defaultdict, dict)
输出:
True
使用dict
,当一个不存在的键被传递到字典中时,会触发__missing__
方法,它持有的default_factory
属性被设置为None
,因此导致KeyError
异常。然而,通过default_dict
,当一个不存在的键被传递到 dictionary 时,它触发了__missing__
方法的default_factory
属性,它持有一个factory
,返回一个缺省值。
例如,我们可以有一个defaultdict
dictionary,它持有factory
函数,list
,当传递一个不存在的键时,它返回一个空列表。
from collections import defaultdict
ddict = defaultdict(list)
print(ddict["one"])
输出:
[]
尽管ddict
没有键one
,但由于传递了factory
函数,它返回的值是一个空列表。它甚至在这样的表达式后创建了键。
from collections import defaultdict
ddict = defaultdict(list)
print(ddict["one"])
print(ddict["two"].append(1))
print(ddict)
输出结果:
[]
defaultdict(<class 'list'>, {'one': [], 'two': [1]})
所以,在ddict["one"]
和ddict["two"].append(1)
语句之后,它创建了各自的键和基于list
函数的相应值。对于第二个Python语句,它基于default_factory
属性函数创建了空列表,然后将值1
附加到其中。
在defaultdict
数据类型中典型的数值分组可以与dict
数据类型的处理方式不同。
sentence = 'the man loves oranges, but also cares a great deal about apples'
letterStore = dict()
for i in sentence:
if k not in letterStore:
letterStore[i] = 1
continue
letterStore[i] += 1
print(letterStore.items())
输出:
dict_items([('t', 4), ('h', 1), ('e', 7), (' ', 11), ('m', 1), ('a', 9), ('n', 2), ('l', 4), ('o', 4), ('v', 1), ('s', 5), ('r', 3), ('g', 2), (',', 1), ('b', 2), ('u', 2), ('c', 1), ('d', 1), ('p', 2)])
上述的字母分组可以通过使用defaultdict
来轻松完成。与其让代码块检查字母是否已经在letterStore
绑定中创建初始编号,我们可以使用defaultdict
,通过factory
函数 –int
来实现。
from collections import defaultdict
sentence = 'the man loves oranges, but also cares a great deal about apples'
letterStore = defaultdict(int)
for i in sentence:
letterStore[i] += 1
print(letterStore.items())
输出:
dict_items([('t', 4), ('h', 1), ('e', 7), (' ', 11), ('m', 1), ('a', 9), ('n', 2), ('l', 4), ('o', 4), ('v', 1), ('s', 5), ('r', 3), ('g', 2), (',', 1), ('b', 2), ('u', 2), ('c', 1), ('d', 1), ('p', 2)])
所以,通过这个,我们知道,当一个键不存在时,__missing__
方法被调用。它的属性default_factory
也被触发了,它持有一个返回值的函数。
然而,我们可以创建一个defaultdict
的defaultdict
吗?是的,但我们如何才能做到呢?因为如果你把一个defaultdict
传给另一个defaultdict
,就会引起错误。
from collections import defaultdict
d = defaultdict(defaultdict(int))
print(d)
输出:
Traceback (most recent call last):
File "c:UsersUSERDesktopJStest.py", line 3, in <module>
d = defaultdict(defaultdict(int))
TypeError: first argument must be callable or None
当我们运行代码时,抛出了一个TypeError
,而这是由于d = defaultdict(defaultdict(int))
,这一行说的是first argument must be callable or None
。
通过这些信息,我们可以推断出,我们没有传递一个可调用的(一个函数)或None(default_factory
持有的默认值),这是因为defaultdict(int)
是不可调用的。然而,它是一个'collections.defaultdict'
。
因此,我们需要找到一种方法来传递一个可调用的东西,这就是lambda
的作用。
lambda
我们可以创建一个可以被调用的匿名函数(一个可调用的)。因此,对于上层的 ,我们可以传递一个指向 的 函数,当我们传递一个不存在的键时,它将被调用。defaultdict
defaultdict(int)
lambda
lambda
函数调用内部defaultdict
中的factory
函数,并返回其值,该值将被设置为键值。
from collections import defaultdict
d = defaultdict(lambda: defaultdict(int))
print(d)
输出:
defaultdict(<function <lambda> at 0x000001F6B9383E20>, {})
为了表明它工作正常,我们可以使用平方符号访问顶层的defaultdict
和内层的defaultdict
,以查看它们的默认值,这些值应分别传递给lambda
和int
函数。
print(d[0])
print(d[0][0])
输出结果:
defaultdict(<class 'int'>, {})
0