collections.defaultdict如何运作?

Lan*_*ton 455 python dictionary default-value 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)]
Run Code Online (Sandbox Code Playgroud)

>>> 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])]
Run Code Online (Sandbox Code Playgroud)

参数intlist用于什么?

Sve*_*ach 516

通常,KeyError如果您尝试使用当前不在字典中的键获取项目,则Python字典会抛出一个.该defaultdict相反只会创建您尝试访问(当然前提是它们还不存在)的任何项目.要创建这样的"默认"项,它会调用传递给构造函数的函数对象(更准确地说,它是一个任意的"可调用"对象,包括函数和类型对象).对于第一个示例,使用创建默认项int(),这将返回整数对象0.对于第二个示例,使用创建默认项list(),这将返回一个新的空列表对象.

  • @Ambareesh`d.get(key,default)`永远不会修改您的字典–它只会返回默认值,而使字典保持不变。另一方面,`defaultdict`会将_key插入字典,如果还没有的话。这是一个很大的差异。查看问题中的示例以了解原因。 (16认同)
  • 它与使用d.get(key,default_val)在功能上有所不同吗? (3认同)
  • @Sean `defaultdict` 调用您传入的任何构造函数。如果您传入 a 类型 `T`,则将使用 `T()` 构造值。并非所有类型都可以在不传递任何参数的情况下构造。如果你想构造这样的类型,你需要一个包装函数,或者类似 `functools.partial(T, arg1, arg2)` 的东西。 (3认同)
  • 或者更简单:lambda。`defaultdict(lambda : T(arg1, arg2))`。 (3认同)

orl*_*rlp 197

defaultdict表示如果在字典中找不到某个键,则会KeyError创建一个新条目而不是被抛出.这个新条目的类型由defaultdict的参数给出.

例如:

somedict = {}
print(somedict[3]) # KeyError

someddict = defaultdict(int)
print(someddict[3]) # print int(), thus 0
Run Code Online (Sandbox Code Playgroud)

  • 或者如果你只想返回"bar":somedict = defaultdict(lambda:"bar") (13认同)
  • "这对新对的类型由defaultdict的参数给出." 请注意,参数可以是**任何**可调用对象 - 而不仅仅是类型函数.例如,如果foo是返回"bar"的函数,则foo可以用作默认dict的参数,如果访问了非存在键,则其值将设置为"bar". (10认同)

小智 85

defaultdict

"标准字典包括方法setdefault(),用于检索值并在值不存在时建立默认值.相反,defaultdict让调用者在初始化容器时预先指定默认值(要返回的值)."

Doug HellmannPython标准库定义

如何使用defaultdict

导入defaultdict

>>> from collections import defaultdict
Run Code Online (Sandbox Code Playgroud)

初始化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>, {})
Run Code Online (Sandbox Code Playgroud)

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

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

要么

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

它是如何工作的

作为标准字典的子类,它可以执行所有相同的功能.

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

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

如果您想更改默认值overwrite 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})
Run Code Online (Sandbox Code Playgroud)

要么

>>> 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})
Run Code Online (Sandbox Code Playgroud)

问题中的例子

例1

由于int已作为default_factory传递,因此默认情况下任何未知键都将返回0.

现在,当字符串在循环中传递时,它将增加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})
Run Code Online (Sandbox Code Playgroud)

例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]})
Run Code Online (Sandbox Code Playgroud)


var*_*wal 18

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

基本上,参数intlist是您传递的函数.请记住,Python接受函数名作为参数.int默认返回0,当使用括号调用时,list返回空列表.

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


dim*_*ion 14

字典是存储数据以便以后通过名称(密钥)检索的便捷方式.键必须是唯一的,不可变的对象,通常是字符串.字典中的值可以是任何值.对于许多应用程序,值是简单类型,如整数和字符串.

当字典中的值是集合(列表,字符串等)时,它会变得更有趣.在这种情况下,必须在第一次使用给定键时初始化值(空列表或字典).虽然手动操作相对容易,但defaultdict类型可以自动化并简化这些操作.defaultdict的工作原理与普通的dict完全相同,但是它使用一个不带参数的函数("default factory")进行初始化,并为不存在的键提供默认值.

defaultdict永远不会引发KeyError.任何不存在的键都会获取默认工厂返回的值.

from collections import defaultdict
ice_cream = defaultdict(lambda: 'Vanilla')

ice_cream['Sarah'] = 'Chunky Monkey'
ice_cream['Abdul'] = 'Butter Pecan'

print(ice_cream['Sarah'])
>>>Chunky Monkey

print(ice_cream['Joe'])
>>>Vanilla
Run Code Online (Sandbox Code Playgroud)

这是另一个例子如何使用defaultdict如何降低复杂性

from collections import defaultdict
# Time complexity O(n^2)
def delete_nth_naive(array, n):
    ans = []
    for num in array:
        if ans.count(num) < n:
            ans.append(num)
    return ans

# Time Complexity O(n), using hash tables.
def delete_nth(array,n):
    result = []
    counts = defaultdict(int)

    for i in array:
        if counts[i] < n:
            result.append(i)
            counts[i] += 1
    return result


x = [1,2,3,1,2,1,2,3]
print(delete_nth(x, n=2))
print(delete_nth_naive(x, n=2))
Run Code Online (Sandbox Code Playgroud)

总之,只要您需要字典,并且每个元素的值应以默认值开头,请使用defaultdict.


Die*_*roz 12

的行为defaultdict可以很容易地在每次调用中使用dict.setdefault而不是模仿d[key]

换句话说,代码:

from collections import defaultdict

d = defaultdict(list)

print(d['key'])                        # empty list []
d['key'].append(1)                     # adding constant 1 to the list
print(d['key'])                        # list containing the constant [1]
Run Code Online (Sandbox Code Playgroud)

相当于:

d = dict()

print(d.setdefault('key', list()))     # empty list []
d.setdefault('key', list()).append(1)  # adding constant 1 to the list
print(d.setdefault('key', list()))     # list containing the constant [1]
Run Code Online (Sandbox Code Playgroud)

唯一的区别是,使用defaultdict列表构造函数只调用一次,而使用dict.setdefault列表构造函数调用更频繁(但如果确实需要,可以重写代码以避免这种情况)。

有些人可能会争辩说有一个性能考虑,但这个话题是一个雷区。 例如,这篇文章表明使用 defaultdict 并没有很大的性能提升。

IMO,defaultdict 是一个集合,它增加了代码的混乱而不是好处。对我没用,但其他人可能会有不同的想法。


cod*_*ina 10

那么,defaultdict 在以下情况下也会引发 keyerror:

from collections import defaultdict
d = defaultdict()
print(d[3]) #raises keyerror
Run Code Online (Sandbox Code Playgroud)

永远记住给 defaultdict 提供参数,例如

d = defaultdict(int)
Run Code Online (Sandbox Code Playgroud)


Edw*_*alk 7

我自己的2¢:你也可以继承defaultdict:

class MyDict(defaultdict):
    def __missing__(self, key):
        value = [None, None]
        self[key] = value
        return value
Run Code Online (Sandbox Code Playgroud)

对于非常复杂的案例,这可能会派上用场.


小智 7

简而言之:

defaultdict(int)- 参数 int 表示值将是 int 类型。

defaultdict(list)- 参数列表指示值将是列表类型。


Jon*_*mbs 6

由于问题是"如何运作",一些读者可能希望看到更多的细节.具体而言,所讨论的方法是__missing__(key)方法.请参阅:https://docs.python.org/2/library/collections.html#defaultdict-objects.

更具体地说,这个答案显示了如何以__missing__(key)实用的方式使用:https: //stackoverflow.com/a/17956989/1593924

为了澄清"可调用"的含义,这里是一个交互式会话(从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})
Run Code Online (Sandbox Code Playgroud)

这是defaultdict的最典型用法(除了毫无意义地使用x变量).您可以使用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
Run Code Online (Sandbox Code Playgroud)

相反,以下工作是因为它传递了一个简单的函数(它在运行中创建一个无名函数,它不带参数并且总是返回0):

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

并使用不同的默认值:

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


小智 6

defaultdict 工具是 Python 集合类中的一个容器。它类似于通常的字典 (dict) 容器,但有一个区别:值字段的数据类型在初始化时指定。

例如:

from collections import defaultdict

d = defaultdict(list)

d['python'].append("awesome")

d['something-else'].append("not relevant")

d['python'].append("language")

for i in d.items():

    print i
Run Code Online (Sandbox Code Playgroud)

这打印:

('python', ['awesome', 'language'])
('something-else', ['not relevant'])
Run Code Online (Sandbox Code Playgroud)