Python 的 collections.defaultdict returns 默认值是正确的,除非没有首先引用该键

Python's collections.defaultdict returns default value correctly unless the key isn't referenced first

基本上,如果我设置 defaultdict 并按键引用它,它将正常工作,return 我设置为默认值。但是,如果我在其上使用 .get(),则默认值不是 returned。这是我能给出的最简单的例子。

basedict = defaultdict(dict)
assert(basedict['junk'] == {}) # Pass
assert(basedict.get('junk') == {}) # Pass
assert(basedict.get('popcorn') == {}) # Fail

为了完成,我正在处理一个个的字典,我最初遇到问题的代码看起来更像这样

from collections import defaultdict

basedict = defaultdict(dict)
assert(basedict['junk'] == {})

basedict[69] = defaultdict(lambda: 1000)
assert(basedict[69]['junk'] == 1000)
assert(basedict[69].get('junk') == 1000)
assert(basedict[69].get('junk', 420) == 1000)

# The above works fine, but if I call .get on a default dict using a key I've
# never referenced before it returns None or the .get supplied default value
assert(basedict[69].get('garbage') == 1000) # Returns None
assert(basedict[69].get('garbage', 420) == 1000) # Returns 420
assert(basedict[69].get('dumpster', 420) == 1000) # Returns 420

# But if I place a an assert before the calling .get(garbage) that 
# checks basedict[69]['garbage'] then the asserts after work until I get 
# to 'dumpster' at which point it fails again
# It also fails if I set the defaultdict to something other than a lambda
basedict[7] = defaultdict(dict)
assert(basedict[7]['taco'] == {}) # Pass
assert(basedict[7].get('taco') == {}) # Pass
assert(basedict[7].get('burrito') == {}) # Fail

defaultdict.get() 填充密钥,不。这是 设计,否则会破坏该方法的目的。这同样适用于会员测试:

>>> from collections import defaultdict
>>> d = defaultdict(dict)
>>> 'foo' in d
False
>>> d['foo']
{}
>>> 'foo' in d
True

如果您需要为丢失的密钥调用默认工厂,请使用 defaultdict.__getitem__(例如 defaultdict_instance[key])。

如果您需要设置默认值其他而不是工厂提供的值,请使用dict.setdefault():

>>> d = defaultdict(dict)
>>> d.setdefault('bar', 42)
42
>>> d.setdefault('bar', 30)
42
>>> d
defaultdict(<type 'dict'>, {'bar': 42})

如果您只需要获取默认值,请使用 dict.get():

>>> d = defaultdict(dict)
>>> d.get('bar', {}).get('baz', 1000)
1000

请注意,我链接了 .get() 调用;如果缺少第一个键,第一个 .get() returns 一个空字典。

我最近 运行 遇到了这个问题,基本上不得不做这样的事情:

from collections import defaultdict

class BetterDict(defaultdict):
    def get(self, item, default=None):
        # default is not really used, but leaving here for compatibility
        # This will either return the actual value, or the defaultdict's
        # default, as generated by default_factory
        return self.__getitem__(item)

现在:

basedict = BetterDict(dict)
assert(basedict['junk'] == {}) # Pass
assert(basedict.get('junk') == {}) # Pass
assert(basedict.get('popcorn') == {}) # Pass