如何使用函数自动从非现有键创建值

时间:2017-06-28 04:29:15

标签: python dictionary defaultdict

背景:

假设我有一个功能(当然,实际上这将是一个更复杂的功能):

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不存在时,它应该调用{{1}而不是f(x)来创建默认值?

2 个答案:

答案 0 :(得分:3)

基于the docs,您可以通过继承defaultdict并覆盖__missing__来获得所需的行为:

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

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

这里快速demo

答案 1 :(得分:2)

您可以构建自己的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是字典对象的包装器,这使您可以轻松地对字典数据类型进行子类化。

查看官方文档。