collections.defaultdict是如何工作的?

我已经阅读了python文档中的例子,但仍然无法弄清楚这个方法的含义。 有人可以帮忙吗? 这里是两个python文档的例子

>>> from collections import defaultdict >>> s = 'mississippi' >>> d = defaultdict(int) >>> for k in s: ... d[k] += 1 ... >>> d.items() [('i', 4), ('p', 2), ('s', 4), ('m', 1)] 

 >>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] >>> d = defaultdict(list) >>> for k, v in s: ... d[k].append(v) ... >>> d.items() [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] 

参数intlist是为了什么?

通常,如果您尝试使用当前不在字典中的键获取项目,则Python字典会引发KeyError 。 相比之下, defaultdict只会创build您尝试访问的任何项目(当然,这些项目目前还不存在)。 为了创build这样一个“默认”的项目,它调用你在构造函数中传递的函数对象(更确切地说,它是一个任意的“可调用”对象,它包括函数和types对象)。 对于第一个示例,使用int()创build默认项目,这将返回整数对象0 。 对于第二个示例,使用list()创build默认项目,这将返回一个新的空列表对象。

defaultdict表示如果在字典中没有find键,则不会抛出KeyError ,而是创build一个新条目。 这个新条目的types由defaultdict的参数给出。

例如:

 somedict = {} print(somedict[3]) # KeyError someddict = defaultdict(int) print(someddict[3]) # print int(), thus 0 

defaultdict

“标准字典包含setdefault()方法来获取一个值,如果该值不存在则创build一个默认值。相比之下, defaultdict允许调用者在容器初始化时指定缺省值(返回的值)。

Doug HellmannPython标准库中的例子所定义的

如何使用defaultdict

导入defaultdict

 >>> from collections import defaultdict 

初始化defaultdict

通过传递来初始化它

可作为第一个参数调用(强制)

 >>> d_int = defaultdict(int) >>> d_list = defaultdict(list) >>> def foo(): ... return 'default value' ... >>> d_foo = defaultdict(foo) >>> d_int defaultdict(<type 'int'>, {}) >>> d_list defaultdict(<type 'list'>, {}) >>> d_foo defaultdict(<function foo at 0x7f34a0a69578>, {}) 

** kwargs作为第二个参数(可选)

 >>> d_int = defaultdict(int, a=10, b=12, c=13) >>> d_int defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12}) 

要么

 >>> kwargs = {'a':10,'b':12,'c':13} >>> d_int = defaultdict(int, **kwargs) >>> d_int defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12}) 

它是如何工作的

作为一个标准字典的子类,它可以执行所有相同的function。

但是在传递未知密钥的情况下,它会返回默认值而不是错误。 例如:

 >>> d_int['a'] 10 >>> d_int['d'] 0 >>> d_int defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12, 'd': 0}) 

如果你想改变默认值覆盖default_factory:

 >>> d_int.default_factory = lambda: 1 >>> d_int['e'] 1 >>> d_int defaultdict(<function <lambda> at 0x7f34a0a91578>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0}) 

要么

 >>> def foo(): ... return 2 >>> d_int.default_factory = foo >>> d_int['f'] 2 >>> d_int defaultdict(<function foo at 0x7f34a0a0a140>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0, 'f': 2}) 

问题中的例子

例1

由于int已经作为default_factory传递,任何未知的键默认都会返回0。

现在,string在循环中传递,它将增加d中字母的数量。

 >>> s = 'mississippi' >>> d = defaultdict(int) >>> d.default_factory <type 'int'> >>> for k in s: ... d[k] += 1 >>> d.items() [('i', 4), ('p', 2), ('s', 4), ('m', 1)] >>> d defaultdict(<type 'int'>, {'i': 4, 'p': 2, 's': 4, 'm': 1}) 

例2

由于列表已经作为default_factory传递,所以默认情况下,任何未知的(不存在的)键都将返回[](即列表)。

现在,由于元组列表在循环中传递,它将在d [color]

 >>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] >>> d = defaultdict(list) >>> d.default_factory <type 'list'> >>> for k, v in s: ... d[k].append(v) >>> d.items() [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] >>> d defaultdict(<type 'list'>, {'blue': [2, 4], 'red': [1], 'yellow': [1, 3]}) 

这里有一个很好的defaultdicts解释: http : //ludovf.net/blog/python-collections-defaultdict/

基本上,参数intlist是你传递的函数。 请记住,Python接受函数名称作为参数。 默认情况下, int返回0,当用圆括号调用时, list返回一个空列表。

在普通的字典中,如果在你的例子中我尝试调用d[a] ,我将得到一个错误(KeyError),因为只有m,s,i和p这两个键存在,而且a没有被初始化。 但在defaultdict中,它将函数名称作为参数,当您尝试使用尚未初始化的键时,它只会调用您传入的函数,并将其返回值指定为新键的值。

由于这个问题是关于“它是如何工作的”,所以一些读者可能希望看到更多的细节。 具体来说,所讨论的方法是__missing__(key)方法。 请参阅: https : //docs.python.org/2/library/collections.html#defaultdict-objects 。

更具体地说,这个答案显示如何以实用的方式使用__missing__(key) : https : __missing__(key)

为了澄清“可调用”的意思,这里是一个交互式会话(从2.7.6开始,但也应该在v3中工作):

 >>> x = int >>> x <type 'int'> >>> y = int(5) >>> y 5 >>> z = x(5) >>> z 5 >>> from collections import defaultdict >>> dd = defaultdict(int) >>> dd defaultdict(<type 'int'>, {}) >>> dd = defaultdict(x) >>> dd defaultdict(<type 'int'>, {}) >>> dd['a'] 0 >>> dd defaultdict(<type 'int'>, {'a': 0}) 

这是defaultdict最典型的用法(除了无意义的使用xvariables)。 您可以使用0作为明确的默认值,但不能使用简单的值:

 >>> dd2 = defaultdict(0) Traceback (most recent call last): File "<pyshell#7>", line 1, in <module> dd2 = defaultdict(0) TypeError: first argument must be callable 

相反,下面的工作,因为它传递一个简单的函数(它dynamic创build一个无名的函数,它不带参数,总是返回0):

 >>> dd2 = defaultdict(lambda: 0) >>> dd2 defaultdict(<function <lambda> at 0x02C4C130>, {}) >>> dd2['a'] 0 >>> dd2 defaultdict(<function <lambda> at 0x02C4C130>, {'a': 0}) >>> 

并使用不同的默认值:

 >>> dd3 = defaultdict(lambda: 1) >>> dd3 defaultdict(<function <lambda> at 0x02C4C170>, {}) >>> dd3['a'] 1 >>> dd3 defaultdict(<function <lambda> at 0x02C4C170>, {'a': 1}) >>> 

我自己2¢:你也可以子类defaultdict:

 class MyDict(defaultdict): def __missing__(self, key): value = [None, None] self[key] = value return value 

这对于非常复杂的情况可以派上用场。

标准字典包含setdefault()方法来检索一个值,如果该值不存在,则build立一个默认值。 相比之下,defaultdict允许调用者在容器初始化时指定默认的预设值。

 import collections def default_factory(): return 'default value' d = collections.defaultdict(default_factory, foo='bar') print 'd:', d print 'foo =>', d['foo'] print 'bar =>', d['bar'] 

只要适用于所有的键都具有相同的默认值,这种方法就行得通。 如果默认值是用于聚合或累加值的types(例如,列表,集合或甚至是int),那么它会特别有用。 标准库文档包括几个使用defaultdict的例子。

 $ python collections_defaultdict.py d: defaultdict(<function default_factory at 0x100468c80>, {'foo': 'bar'}) foo => bar bar => default value 

我认为它最好用来代替switch case语句。 想象一下,如果我们有一个switch case case语句如下:

 option = 1 switch(option) { case 1: print '1st option' case 2: print '2nd option' case 3: print '3rd option' default: return 'No such option' } 

python中没有可用的switch case语句。 我们可以使用defaultdict来实现。

 from collections import defaultdict def default_value(): return "Default Value" dd = defaultdict(default_value) dd[1] = '1st option' dd[2] = '2nd option' dd[3] = '3rd option' print(dd[4]) print(dd[5]) print(dd[3]) 

它打印:

 Default Value Default Value 3rd option 

在上面的代码中, dd没有键4或5,因此它打印出一个默认值,我们已经在辅助函数中configuration了它。 这比原始字典更好,如果key不存在,则抛出KeyError 。 由此可见, defaultdict更像是一个switch case语句,我们可以避免一个复杂的if-elif-elif-else块。

从这个网站给我留下了深刻印象的一个很好的例子是:

 >>> from collections import defaultdict >>> food_list = 'spam spam spam spam spam spam eggs spam'.split() >>> food_count = defaultdict(int) # default value of int is 0 >>> for food in food_list: ... food_count[food] += 1 # increment element's value by 1 ... defaultdict(<type 'int'>, {'eggs': 1, 'spam': 7}) >>> 

如果我们尝试访问除eggsspam以外的任何项目,我们将得到0的计数。

文档和解释几乎不言自明:

http://docs.python.org/library/collections.html#collections.defaultdict

作为parameter passing的types函数(int / str等)用于初始化键在dict中不存在的任何给定键的默认值。