标签归档:defaultdict

嵌套的defaultdict defaultdict

问题:嵌套的defaultdict defaultdict

有没有办法使defaultdict也成为defaultdict的默认值?(即无限级递归defaultdict?)

我希望能够做到:

x = defaultdict(...stuff...)
x[0][1][0]
{}

因此,我可以做到x = defaultdict(defaultdict),但这仅是第二层:

x[0]
{}
x[0][0]
KeyError: 0

有一些食谱可以做到这一点。但是,仅使用常规的defaultdict参数就可以做到吗?

请注意,这是在问如何执行无限级递归defaultdict,因此它与Python不同:defaultdict的defaultdict?,这是执行两级defaultdict的方法。

我可能最终会使用模式,但是当我意识到自己不知道该怎么做时,这引起了我的兴趣。

Is there a way to make a defaultdict also be the default for the defaultdict? (i.e. infinite-level recursive defaultdict?)

I want to be able to do:

x = defaultdict(...stuff...)
x[0][1][0]
{}

So, I can do x = defaultdict(defaultdict), but that’s only a second level:

x[0]
{}
x[0][0]
KeyError: 0

There are recipes that can do this. But can it be done simply just using the normal defaultdict arguments?

Note this is asking how to do an infinite-level recursive defaultdict, so it’s distinct to Python: defaultdict of defaultdict?, which was how to do a two-level defaultdict.

I’ll probably just end up using the bunch pattern, but when I realized I didn’t know how to do this, it got me interested.


回答 0

对于任意数量的级别:

def rec_dd():
    return defaultdict(rec_dd)

>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}

当然,您也可以使用lambda来执行此操作,但是我发现lambda的可读性较差。无论如何,它看起来像这样:

rec_dd = lambda: defaultdict(rec_dd)

For an arbitrary number of levels:

def rec_dd():
    return defaultdict(rec_dd)

>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}

Of course you could also do this with a lambda, but I find lambdas to be less readable. In any case it would look like this:

rec_dd = lambda: defaultdict(rec_dd)

回答 1

这里的其他答案告诉您如何创建一个defaultdict包含“无限多个”的defaultdict,但是它们无法解决我认为您最初的需求,即仅具有两个深度的defaultdict。

您可能一直在寻找:

defaultdict(lambda: defaultdict(dict))

您可能更喜欢此构造的原因是:

  • 它比递归解决方案更明确,因此读者可能更容易理解。
  • 这使的“叶” defaultdict可以是除字典之外的其他内容,例如:defaultdict(lambda: defaultdict(list))defaultdict(lambda: defaultdict(set))

The other answers here tell you how to create a defaultdict which contains “infinitely many” defaultdict, but they fail to address what I think may have been your initial need which was to simply have a two-depth defaultdict.

You may have been looking for:

defaultdict(lambda: defaultdict(dict))

The reasons why you might prefer this construct are:

  • It is more explicit than the recursive solution, and therefore likely more understandable to the reader.
  • This enables the “leaf” of the defaultdict to be something other than a dictionary, e.g.,: defaultdict(lambda: defaultdict(list)) or defaultdict(lambda: defaultdict(set))

回答 2

有一个不错的技巧:

tree = lambda: defaultdict(tree)

然后,您可以使用创建自己xx = tree()

There is a nifty trick for doing that:

tree = lambda: defaultdict(tree)

Then you can create your x with x = tree().


回答 3

与BrenBarn的解决方案类似,但是不包含tree两次变量名,因此即使更改了变量字典也可以使用:

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))

然后,您可以创建的每个新xx = tree()


对于该def版本,我们可以使用函数闭包作用域来保护数据结构,以免其tree名称被反弹时现有实例停止工作的缺陷。看起来像这样:

from collections import defaultdict

def tree():
    def the_tree():
        return defaultdict(the_tree)
    return the_tree()

Similar to BrenBarn’s solution, but doesn’t contain the name of the variable tree twice, so it works even after changes to the variable dictionary:

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))

Then you can create each new x with x = tree().


For the def version, we can use function closure scope to protect the data structure from the flaw where existing instances stop working if the tree name is rebound. It looks like this:

from collections import defaultdict

def tree():
    def the_tree():
        return defaultdict(the_tree)
    return the_tree()

回答 4

我还将提出更多OOP样式的实现,该实现支持无限嵌套以及正确格式化repr

class NestedDefaultDict(defaultdict):
    def __init__(self, *args, **kwargs):
        super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)

    def __repr__(self):
        return repr(dict(self))

用法:

my_dict = NestedDefaultDict()
my_dict['a']['b'] = 1
my_dict['a']['c']['d'] = 2
my_dict['b']

print(my_dict)  # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}}

I would also propose more OOP-styled implementation, which supports infinite nesting as well as properly formatted repr.

class NestedDefaultDict(defaultdict):
    def __init__(self, *args, **kwargs):
        super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)

    def __repr__(self):
        return repr(dict(self))

Usage:

my_dict = NestedDefaultDict()
my_dict['a']['b'] = 1
my_dict['a']['c']['d'] = 2
my_dict['b']

print(my_dict)  # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}}

回答 5

这是一个递归函数,用于将递归默认字典转换为普通字典

def defdict_to_dict(defdict, finaldict):
    # pass in an empty dict for finaldict
    for k, v in defdict.items():
        if isinstance(v, defaultdict):
            # new level created and that is the new value
            finaldict[k] = defdict_to_dict(v, {})
        else:
            finaldict[k] = v
    return finaldict

defdict_to_dict(my_rec_default_dict, {})

here is a recursive function to convert a recursive default dict to a normal dict

def defdict_to_dict(defdict, finaldict):
    # pass in an empty dict for finaldict
    for k, v in defdict.items():
        if isinstance(v, defaultdict):
            # new level created and that is the new value
            finaldict[k] = defdict_to_dict(v, {})
        else:
            finaldict[k] = v
    return finaldict

defdict_to_dict(my_rec_default_dict, {})

回答 6

我在这里基于安德鲁的答案。如果要从json或现有字典将数据加载到嵌套程序defaultdict中,请参见以下示例:

def nested_defaultdict(existing=None, **kwargs):
    if existing is None:
        existing = {}
    if not isinstance(existing, dict):
        return existing
    existing = {key: nested_defaultdict(val) for key, val in existing.items()}
    return defaultdict(nested_defaultdict, existing, **kwargs)

https://gist.github.com/nucklehead/2d29628bb49115f3c30e78c071207775

I based this of Andrew’s answer here. If you are looking to load data from a json or an existing dict into the nester defaultdict see this example:

def nested_defaultdict(existing=None, **kwargs):
    if existing is None:
        existing = {}
    if not isinstance(existing, dict):
        return existing
    existing = {key: nested_defaultdict(val) for key, val in existing.items()}
    return defaultdict(nested_defaultdict, existing, **kwargs)

https://gist.github.com/nucklehead/2d29628bb49115f3c30e78c071207775


collections.defaultdict如何工作?

问题: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])]

参数int和目的list是什么?

I’ve read the examples in python docs, but still can’t figure out what this method means. Can somebody help? Here are two examples from the python docs

>>> 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)]

and

>>> 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])]

the parameters int and list are for what?


回答 0

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

Usually, a Python dictionary throws a KeyError if you try to get an item with a key that is not currently in the dictionary. The defaultdict in contrast will simply create any items that you try to access (provided of course they do not exist yet). To create such a “default” item, it calls the function object that you pass to the constructor (more precisely, it’s an arbitrary “callable” object, which includes function and type objects). For the first example, default items are created using int(), which will return the integer object 0. For the second example, default items are created using list(), which returns a new empty list object.


回答 1

defaultdict表示如果在字典中找不到键,则KeyError创建新条目而不是引发键。此新条目的类型由defaultdict的参数给出。

例如:

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

someddict = defaultdict(int)
print(someddict[3]) # print int(), thus 0

defaultdict means that if a key is not found in the dictionary, then instead of a KeyError being thrown, a new entry is created. The type of this new entry is given by the argument of defaultdict.

For example:

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

someddict = defaultdict(int)
print(someddict[3]) # print int(), thus 0

回答 2

defaultdict

“标准字典包括setdefault()方法,该方法用于检索值并在该值不存在时建立默认值。相比之下,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})

如何运作

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

但是,如果传递未知密钥,它将返回默认值而不是错误。例如:

>>> 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。

现在,当字符串在循环中传递时,它将增加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传递,因此默认情况下,任何未知(不存在)键都将返回[](即list)。

现在,在循环中传递元组列表时,它将在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]})

defaultdict

“The standard dictionary includes the method setdefault() for retrieving a value and establishing a default if the value does not exist. By contrast, defaultdict lets the caller specify the default(value to be returned) up front when the container is initialized.”

as defined by Doug Hellmann in The Python Standard Library by Example

How to use defaultdict

Import defaultdict

>>> from collections import defaultdict

Initialize defaultdict

Initialize it by passing

callable as its first argument(mandatory)

>>> 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 as its second argument(optional)

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

or

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

How does it works

As is a child class of standard dictionary, it can perform all the same functions.

But in case of passing an unknown key it returns the default value instead of error. For ex:

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

In case you want to change default value 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})

or

>>> 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})

Examples in the Question

Example 1

As int has been passed as default_factory, any unknown key will return 0 by default.

Now as the string is passed in the loop, it will increase the count of those alphabets in 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})

Example 2

As a list has been passed as default_factory, any unknown(non-existent) key will return [ ](ie. list) by default.

Now as the list of tuples is passed in the loop, it will append the value in the 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]})

回答 3

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

当字典中的值是集合(列表,字典等)时,它将变得更加有趣。在这种情况下,必须在首次使用给定键时初始化值(空列表或字典)。尽管这相对容易手动完成,但是defaultdict类型可自动执行并简化此类操作。defaultdict的工作原理与普通dict完全相同,但是它使用不带任何参数并为不存在的键提供默认值的函数(“默认工厂”)进行了初始化。

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

这是另一个示例,说明如何使用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))

总之,每当需要字典时,每个元素的值都应以默认值开头,请使用defaultdict。

Dictionaries are a convenient way to store data for later retrieval by name (key). Keys must be unique, immutable objects, and are typically strings. The values in a dictionary can be anything. For many applications, the values are simple types such as integers and strings.

It gets more interesting when the values in a dictionary are collections (lists, dicts, etc.) In this case, the value (an empty list or dict) must be initialized the first time a given key is used. While this is relatively easy to do manually, the defaultdict type automates and simplifies these kinds of operations. A defaultdict works exactly like a normal dict, but it is initialized with a function (“default factory”) that takes no arguments and provides the default value for a nonexistent key.

A defaultdict will never raise a KeyError. Any key that does not exist gets the value returned by the default factory.

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

Here is another example on How using defaultdict, we can reduce complexity

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))

In conclusion, whenever you need a dictionary, and each element’s value should start with a default value, use a defaultdict.


回答 4

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

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

在普通词典中,如果在您的示例中尝试调用d[a],则会出现错误(KeyError),因为仅存在键m,s,i和p,而键a尚未初始化。但是在defaultdict中,它将函数名称作为参数,当您尝试使用尚未初始化的键时,它只是调用您传入的函数,并将其返回值分配为新键的值。

There is a great explanation of defaultdicts here: http://ludovf.net/blog/python-collections-defaultdict/

Basically, the parameters int and list are functions that you pass. Remember that Python accepts function names as arguments. int returns 0 by default and list returns an empty list when called with parentheses.

In normal dictionaries, if in your example I try calling d[a], I will get an error (KeyError), since only keys m, s, i and p exist and key a has not been initialized. But in a defaultdict, it takes a function name as an argument, when you try to use a key that has not been initialized, it simply calls the function you passed in and assigns its return value as the value of the new key.


回答 5

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

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

为了阐明“ callable”的含义,这是一个交互式会话(来自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的最典型用法(除了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

相反,下面的方法起作用了,因为它传入了一个简单的函数(它动态创建了一个不带参数的无名称函数,并且始终返回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})
>>> 

Since the question is about “how it works”, some readers may want to see more nuts and bolts. Specifically, the method in question is the __missing__(key) method. See: https://docs.python.org/2/library/collections.html#defaultdict-objects .

More concretely, this answer shows how to make use of __missing__(key) in a practical way: https://stackoverflow.com/a/17956989/1593924

To clarify what ‘callable’ means, here’s an interactive session (from 2.7.6 but should work in v3 too):

>>> 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})

That was the most typical use of defaultdict (except for the pointless use of the x variable). You can do the same thing with 0 as the explicit default value, but not with a simple value:

>>> dd2 = defaultdict(0)

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

Instead, the following works because it passes in a simple function (it creates on the fly a nameless function which takes no arguments and always returns 0):

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

And with a different default value:

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

回答 6

我自己的2¢:您还可以将defaultdict子类化:

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

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

My own 2¢: you can also subclass defaultdict:

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

This could come in handy for very complex cases.


回答 7

的行为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]

等效于:

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]

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

有人可能会认为有性能方面的考虑,但是这个话题是一个雷区。 这篇文章显示,例如,使用defaultdict不会带来很大的性能提升。

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

The behavior of defaultdict can be easily mimicked using dict.setdefault instead of d[key] in every call.

In other words, the code:

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]

is equivalent to:

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]

The only difference is that, using defaultdict, the list constructor is called only once, and using dict.setdefault the list constructor is called more often (but the code may be rewriten to avoid this, if really needed).

Some may argue there is a performance consideration, but this topic is a minefield. This post shows there isn’t a big performance gain in using defaultdict, for example.

IMO, defaultdict is a collection that adds more confusion than benefits to the code. Useless for me, but others may think different.


回答 8

defaultdict工具是Python的collections类中的容器。它与通常的字典(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

打印:

('python', ['awesome', 'language'])
('something-else', ['not relevant'])

The defaultdict tool is a container in the collections class of Python. It’s similar to the usual dictionary (dict) container, but it has one difference: The value fields’ data type is specified upon initialization.

For example:

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

This prints:

('python', ['awesome', 'language'])
('something-else', ['not relevant'])

回答 9

我认为最好用它来代替switch case语句。假设我们有一个switch 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'
}

switchpython中没有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,因此它打印出了我们在辅助函数中配置的默认值。这比原始字典好得多,在原始字典中,KeyError如果不存在键,则抛出a 。由此可见,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。

I think its best used in place of a switch case statement. Imagine if we have a switch case statement as below:

option = 1

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

There is no switch case statements available in python. We can achieve the same by using 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])

It prints:

Default Value
Default Value
3rd option

In the above snippet dd has no keys 4 or 5 and hence it prints out a default value which we have configured in a helper function. This is quite nicer than a raw dictionary where a KeyError is thrown if key is not present. From this it is evident that defaultdict more like a switch case statement where we can avoid a complicated if-elif-elif-else blocks.

One more good example that impressed me a lot from this site is:

>>> 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})
>>>

If we try to access any items other than eggs and spam we will get a count of 0.


回答 10

如果不使用defaultdict,则可能会为看不见的键分配新值,但无法对其进行修改。例如:

import collections
d = collections.defaultdict(int)
for i in range(10):
  d[i] += i
print(d)
# Output: defaultdict(<class 'int'>, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9})

import collections
d = {}
for i in range(10):
  d[i] += i
print(d)
# Output: Traceback (most recent call last): File "python", line 4, in <module> KeyError: 0

Without defaultdict, you can probably assign new values to unseen keys but you cannot modify it. For example:

import collections
d = collections.defaultdict(int)
for i in range(10):
  d[i] += i
print(d)
# Output: defaultdict(<class 'int'>, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9})

import collections
d = {}
for i in range(10):
  d[i] += i
print(d)
# Output: Traceback (most recent call last): File "python", line 4, in <module> KeyError: 0

回答 11

好吧,在以下情况下,defaultdict也会引发keyerror:

    from collections import defaultdict
    d = defaultdict()
    print(d[3]) #raises keyerror

始终记得将参数传递给defaultdict,例如defaultdict(int)。

Well, defaultdict can also raise keyerror in the following case:

    from collections import defaultdict
    d = defaultdict()
    print(d[3]) #raises keyerror

Always remember to give argument to the defaultdict like defaultdict(int).


回答 12

标准字典包含setdefault()方法,该方法用于检索值并在该值不存在时建立默认值。相比之下,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']

只要所有键都具有相同的默认值,此方法就可以很好地工作。如果默认值是用于聚合或累积值的类型(例如列表,集合甚至int),则它特别有用。标准库文档包括使用这种方式使用defaultdict的几个示例。

$ python collections_defaultdict.py

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

The standard dictionary includes the method setdefault() for retrieving a value and establishing a default if the value does not exist. By contrast, defaultdict lets the caller specify the default up front when the container is initialized.

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']

This works well as long as it is appropriate for all keys to have the same default. It can be especially useful if the default is a type used for aggregating or accumulating values, such as a list, set, or even int. The standard library documentation includes several examples of using defaultdict this way.

$ python collections_defaultdict.py

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

回答 13

简而言之:

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

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

In short:

defaultdict(int) – the argument int indicates that the values will be int type.

defaultdict(list) – the argument list indicates that the values will be list type.


回答 14

文档和说明几乎是不言自明的:

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

作为参数传递的类型函数(int / str等)用于为字典中不存在该键的任何给定键初始化默认值。

The documentation and the explanation are pretty much self-explanatory:

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

The type function(int/str etc.) passed as an argument is used to initialize a default value for any given key where the key is not present in the dict.