如何使用函数从不存在的键自动创建值

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

背景:

假设我有一个函数(当然实际上这会是一个更复杂的函数):

def f(x):
    return str(x)

如果我想存储值以避免不必要的重新计算,我可以像这样创建一个 dict

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

但是如果我事先不知道我可能需要哪些值,例如 10my_dict[10] 显然会生成 KeyError

解决这个问题的一种方法是:

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

get_value(10)

问题: 这似乎与 defaultdict 非常相似:有没有办法使直观的(但损坏的)my_dict = defaultdict(f) 工作,即当键 x 不存在时,它应该调用 f(x) 而不是 f() 来创建默认值?

基于 the docs,您可以通过继承 defaultdict 并覆盖 __missing__:

来获得您想要的行为
from collections import defaultdict
class betterdefault(defaultdict):
    def __missing__(self, key):
        return self.default_factory(key)

现在,你想用一些额外的逻辑来充实它,例如,如果 self.default_factory 是 None,则抛出 KeyError,就像他们在文档中提到的那样.希望这能为您指明正确的方向。

这是一个快速的 demo

您可以构建自己的 dict 数据类型。在您的情况下,__missing__ 会有所帮助。如果没有密钥,__missing__ 方法会触发您的自定义工作。下面是一个简单的例子。

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}

另请注意,UserDict 是字典对象的包装器,使您可以轻松地对字典数据类型进行子类化。

查看官方文档。