defaultdict vs dict元素初始化

Deu*_*ius 4 python dictionary defaultdict

我正在尝试优化脚本的性能,该脚本在给出的每个单词的词典中查找相似的单词.

每个唯一的单词将被分成字母n-gram,并且对于每个n-gram,词典返回包含相同字母n-gram的单词列表.然后将此列表中的每个单词作为键添加到字典中,并将其值加1.这给了我一个具有相应频率分数的类似单词的字典.

word_dict = {}
get = word_dict.get
for letter_n_gram in word:
    for entry in lexicon[n_gram]:
        word_dict[entry] = get(entry, 0) + 1
Run Code Online (Sandbox Code Playgroud)

这个实现有效,但是通过切换dictfor 可以更快地运行脚本collections.defaultdict.

word_dd = defaultdict(int)
for letter_n_gram in word:
    for entry in lexicon[n_gram]:
        word_dd[entry] += 1
Run Code Online (Sandbox Code Playgroud)

没有其他代码被更改.

我的印象是两个代码片段(最重要的是分数添加)应该以完全相同的方式工作,即如果密钥存在,将其值增加1,如果它不存在,则创建密钥并将值设置为1.

但是,在运行新代码之后,某些键的值为0,我觉得这在逻辑上是不可能的.

我的逻辑或defaultdict功能知识是否有缺陷?如果没有,如何将任何值word_dd设置为0?

编辑:我也非常确定脚本中没有其他部分会扭曲这些结果,因为我使用以下代码在显示代码后立即测试字典:

for item in word_dd.iteritems():
    if item[1] == 0:
        print "Found zero value element"
        break
Run Code Online (Sandbox Code Playgroud)

the*_*eye 6

当您访问a中的某个键时defaultdict,如果它不存在,则会自动创建该键.由于我们具有int默认的工厂函数,因此它会创建密钥并提供默认值0.

from collections import defaultdict
d = defaultdict(int)
print d["a"]
# 0
print d
# defaultdict(<type 'int'>, {'a': 0})
Run Code Online (Sandbox Code Playgroud)

因此,在访问密钥之前,您应确保它存在于defaultdict实例中,如下所示

print "a" in d
# False
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 6

任何项目对密钥的访问都将实现该值:

>>> from collections import defaultdict
>>> d = defaultdict(int)
>>> d['foo']
0
Run Code Online (Sandbox Code Playgroud)

使用包含来测试存在而不是:

>>> 'bar' in d
False
>>> 'foo' in d
True
Run Code Online (Sandbox Code Playgroud)

既然你在计算n-gram,你可能也想看一下collections.Counter():

from collections import Counter

word_counter = Counter()
for letter_n_gram in word:
    word_counter.update(lexicon[n_gram])
Run Code Online (Sandbox Code Playgroud)

其中Counter.update()将更新lexicon[n_gram]表达式返回的所有条目的计数.

就像defaultdict(int),Counter()对象自动实现值,默认为整数0.

  • @Deutherius:在你的字典中你可以拥有'0`值的唯一**方式是访问密钥(所以`字典[key]`在字典中没有定义密钥的任何地方),或直接分配`0`(通过赋值,扩充赋值或`.update()`). (2认同)