简体   繁体   中英

How to automatically create value from non existing key with a function

Backgroud:

Let's say I have a function (of course in reality that would be a more complex function):

def f(x):
    return str(x)

If I want to store values to avoid unnecessary recomputation, I can create a dict like this:

my_dict = {x: f(x) for x in range(5)}

But then if I don't know in advance which values I may need, for example 10 , my_dict[10] obviously generates a KeyError .

One way around this could be:

my_dict = {}
def get_value(x):
    if x not in my_dict:
        my_dict[x] = f(x)
    return my_dict[x]

get_value(10)

Question: This seems very similar to defaultdict : is there a way to make the intuitive (but broken) my_dict = defaultdict(f) work, ie when a key x doesn't exist, it should call f(x) instead of f() to create the default value?

Based on the docs , you might be able to get the behavior you want by subclassing defaultdict and overriding __missing__ :

from collections import defaultdict
class betterdefault(defaultdict):
    def __missing__(self, key):
        return self.default_factory(key)

Now, you'd want to flesh that out with a little extra logic, eg throw KeyError if self.default_factory is None, stuff like that which they mention in the docs. Hope this points you in the right direction.

Here's a quick demo

you can build your own dict data type. in your case, __missing__ will help. if there is no key, __missing__ method triggers your custom work. below is a simple example.

from collections import UserDict
class MyDict(UserDict):
    def __missing__(self, key):
        self[key] = 2*key
        return self[key]

if __name__ == '__main__': # test
    a = MyDict((x, 2*x) for x in range(5))
    print(a)
    # {0: 0, 1: 2, 2: 4, 3: 6, 4: 8}
    a[5]
    # 10
    print(a)
    # {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5:10}

also note that UserDict is a wrapper around dictionary objects, making you comfortable to subclassing the dictionary data types.

check the official docs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM