Search code examples
pythondefaultdict

defaultdict `.get` returns item and not none after calling after `[]` operator


I ran this code:

from collections import defaultdict
my_dict = defaultdict(lambda: 6, a=7)
print(repr(my_dict.get("a")))
print(repr(my_dict.get("b")))
print(repr(my_dict["b"]))
print(repr(my_dict.get("b")))

And the output was:

7
None
6
6

Ran it on: 3.13.1 (tags/v3.13.1:0671451, Dec 3 2024, 19:06:28) [MSC v.1942 64 bit (AMD64)].

As you can see, when I called my_dict.get("b") before calling my_dict["b"], it returned None. But after I called my_dict.get("b"), it returned None.

According to the docs, it should return the default computed by the factory only at the my_dict["b"] call (__getitem__() method), so why at the second call of: my_dict.get("b"), it returned the computed value? Is it an expected value, or a bug?


Solution

  • You are misunderstanding the API, this is explicitly addressed here the docs:

    If default_factory is not None, it is called without arguments to provide a default value for the given key, this value is inserted in the dictionary for the key, and returned.

    Emphasis added. So whenever you use mydict[x], and the default factory is used, it is internally set to that value. So therefore, if you use .get, it simply retrieves the value that was set. This is how it's supposed to work.

    IOW, for defaultdict objects, __getitem__ is potentially a mutator method.

    Another way of thinking about it is that it works like dict.setdefault:

    >>> mydict = {'a':1}
    >>> mydict.setdefault('a', 42)
    1
    >>> mydict
    {'a': 1}
    >>> mydict.setdefault('b', 42)
    42
    >>> mydict
    {'a': 1, 'b': 42}