dict和collections.defaultdict有什么区别?

68 投票
4 回答
49123 浏览
提问于 2025-04-16 20:54

我在查看彼得·诺维格的代码,他讲的是如何写简单的拼写检查器。在一开始,他用这段代码把单词放进一个字典里。

def train(features):
    model = collections.defaultdict(lambda: 1)
    for f in features:
        model[f] += 1
    return model

那么,Python里的字典和他这里用的字典有什么区别呢?另外,lambda是用来干嘛的?我查了一下API文档,这里说defaultdict其实是从字典(dict)派生出来的,但我们该怎么决定用哪个呢?

4 个回答

13

让我们深入了解Python字典和Python defaultdict()

Python字典

字典是Python中一种数据结构,它可以以键值对的形式存储数据。

举个例子:

d = {'a': 2, 'b': 5, 'c': 6}

字典的问题

字典使用得很好,但如果遇到缺失的键就麻烦了。假设你在找一个键值对,但字典里没有这个值,这时你可能会遇到一个KeyError的问题。就像这样:

d = {'a': 2, 'b': 5, 'c': 6}
d['z']  # z is not present in dict so it will throw a error

你会看到这样的错误信息:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
    d['z'] 
KeyError: 'z'

解决上述问题的方法

为了克服这个问题,我们可以使用不同的方法:

使用内置函数

setdefault

如果字典中有这个key,就返回它的值。如果没有,就插入一个带有default值的键,并返回default。默认情况下,defaultNone

>>> d = {'a' :2, 'b': 5, 'c': 6}
>>> d.setdefault('z', 0)
0  # returns 0 
>>> print(d)  # add z to the dictionary
{'a': 2, 'b': 5, 'c': 6, 'z': 0}

get

如果字典中有这个key,就返回它的值;如果没有,就返回default。如果没有提供默认值,默认值是None,所以这个方法不会引发KeyError

>>> d = {'a': 2, 'b': 5, 'c': 6}
>>> d.get('z', 0)
0  # returns 0 
>>> print(d)  # Doesn't add z to the dictionary unlike setdefault
{'a': 2, 'b': 5, 'c': 6}

以上两种方法都是解决我们问题的办法,它们不会引发KeyError。除了这两种方法,Python还有一个collections模块可以处理这个问题。接下来我们深入了解一下defaultdict

defaultdict

defaultdict可以在Python的collections模块中找到。你可以这样使用它:

from collections import defaultdict

d = defaultdict(int)

defaultdict构造函数接受一个default_factory作为参数,这个参数是一个可调用的对象。比如说:

  • int:默认值是整数0

  • str:默认值是空字符串""

  • list:默认值是空列表[]

代码:

from collections import defaultdict

d = defaultdict(list)
d['a']  # access a missing key and returns an empty list
d['b'] = 1 # add a key-value pair to dict
print(d)

输出将是defaultdict(<class 'list'>, {'b': 1, 'a': []})

defaultdict的工作方式与get()setdefault()方法相同,那么什么时候使用它们呢?

什么时候使用get()

如果你特别需要返回某个键值对而不想遇到KeyError,并且不希望在字典中更新内容,那么dict.get是合适的选择。它会返回你指定的默认值,但不会修改字典。

什么时候使用setdefault()

如果你需要用默认的键值对来修改原始字典,那么setdefault是合适的选择。

什么时候使用defaultdict

虽然setdefault方法可以用defaultdict实现,但与每次在setdefault中提供默认值不同,我们可以在defaultdict中一次性设置默认值。此外,setdefault可以为不同的键提供不同的默认值。根据使用场景,两者各有优缺点。

在效率方面:

defaultdict > setdefault()get()

defaultdict的速度是get()的两倍!

你可以在这里查看结果。

27

来源:- https://shirishweb.wordpress.com/2017/05/06/python-defaultdict-versus-dict-get/

使用普通字典(dict)

d={}
d['Apple']=50
d['Orange']=20
print(d['Apple'])
print(d['Grapes'])# This gives Key Error

我们可以通过在普通字典中设置默认值来避免出现 KeyError 错误,下面我们来看看怎么做。

d={}
d['Apple']=50
d['Orange']=20
print(d['Apple'])
print(d.get('Apple'))
print(d.get('Grapes',0)) # DEFAULTING

使用默认字典(defaultdict)

from collections import defaultdict
d = defaultdict(int) ## inside parenthesis we say what should be the default value.
d['Apple']=50
d['Orange']=20
print(d['Apple'])
print(d['Grapes']) ##→ This gives Will not give error

使用用户自定义的函数来设置默认值。

from collections import defaultdict
def mydefault():
        return 0

d = defaultdict(mydefault)
d['Apple']=50
d['Orange']=20
print(d['Apple'])
print(d['Grapes'])

总结

  1. 在普通字典中设置默认值是根据具体情况来定的,而在默认字典中,我们可以更普遍地提供默认值。

  2. 使用默认字典的效率是使用普通字典的两倍。想了解更多关于这个性能测试的信息,可以参考下面的链接: https://shirishweb.wordpress.com/2017/05/06/python-defaultdict-versus-dict-get/

69

区别在于,defaultdict 会在你还没有设置某个键的时候,自动给这个键一个默认值。如果你不使用 defaultdict,那么你就得先检查这个键是否存在,如果不存在,就得手动给它设置一个值。

这里的 lambda 是在定义一个默认值的“工厂”。每当需要默认值的时候,这个函数就会被调用。你可以想象,默认值的生成函数可以更复杂一些。

Help on class defaultdict in module collections:

class defaultdict(__builtin__.dict)
 |  defaultdict(default_factory) --> dict with default factory
 |  
 |  The default factory is called without arguments to produce
 |  a new value when a key is not present, in __getitem__ only.
 |  A defaultdict compares equal to a dict with the same items.
 |  

(来自 help(type(collections.defaultdict())))

{}.setdefault 的功能类似,但它接受的是一个值,而不是一个工厂函数。它的作用是如果这个值还不存在,就给它设置一个值……这和 defaultdict 有点不同。

撰写回答