Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python dict with default value based on key

I need a dictionary that is automatically filled with a default value for each accessed key that is missing. I've found defaultdict and some other ways to achieve this, but the problem in my case is that I want the default value for each key to be specific to the key itself.

For example, with defaultdict I can achieve something like this:

from collections import defaultdict
d = defaultdict(lambda: 5)
> d[1] = 3
> d[1]
> 3
> d[2]
> 5

But what if I need the default value for each accessed missing key to be for example key + 5? Something like:

from collections import defaultdict
d = defaultdict(lambda key: key + 5)  # <-- This does not work as defaultdict expects lambda function to be without any parameters
> d[1] = 3
> d[1]
> 3
> d[2]
> 7         <- Calculated from accessed key + 5 (2+5)
> d[5]
> 10        <- Calculated from accessed key + 5 (5+5)

Is there a clean, builtin way to achieve what I need? I know that I can create a subclass of dict and implement this specific functionality at __getitem__ level, but I want to avoid that if possible.

I couldn't find a solution in other answers, so sorry if it is still a duplicate.

like image 650
Cxovrika Avatar asked Jun 14 '26 13:06

Cxovrika


2 Answers

I don't think there is a builtin way of doing this. However, instead of subclassing dict and change getitem, you can subclass defaultdict itself to tell __missing__() to call the default_factory with an argument (the key), rather than without args. It is still a custom class, not a builtin, but it should be quite efficient still.

from collections import defaultdict

class DefaultDict(defaultdict):
    def __missing__(self, key):
        return self.default_factory(key)

Then:

d = DefaultDict(lambda key: key + 5)

d[2]
# 7
like image 177
Pierre D Avatar answered Jun 17 '26 02:06

Pierre D


(I do not have enough reputation to comment, so I am commenting here)

Pierre's top answer does work for setting and getting values in the defaultdict, but it does not add the k-v pair to the dict, so you cannot iterate through all the keys, values, or items.

Instead, add self[key] = self.default_factory(key)

from collections import defaultdict

class DefaultDict(defaultdict):
    def __missing__(self, key):
        self[key] = self.default_factory(key)
        return self[key]
like image 37
Sichao Yang Avatar answered Jun 17 '26 03:06

Sichao Yang