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

Python 如何使用函数从不存在的键自动创建值,python,dictionary,defaultdict,Python,Dictionary,Defaultdict,背景: 假设我有一个函数(当然在现实中,这将是一个更复杂的函数): 如果我想存储值以避免不必要的重新计算,我可以创建一个dict,如下所示: my_dict = {x: f(x) for x in range(5)} 但是如果我事先不知道我可能需要哪些值,例如10,my_dict[10]显然会生成一个KeyError 解决这一问题的一种方法是: my_dict = {} def get_value(x): if x not in my_dict: my_dict[x]

背景:

假设我有一个函数(当然在现实中,这将是一个更复杂的函数):

如果我想存储值以避免不必要的重新计算,我可以创建一个
dict
,如下所示:

my_dict = {x: f(x) for x in range(5)}
但是如果我事先不知道我可能需要哪些值,例如
10
my_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()
来创建默认值?

基于,您可以通过子类化
defaultdict
并重写
\uuuu missing\uuuu
来获得所需的行为:

from collections import defaultdict
class betterdefault(defaultdict):
    def __missing__(self, key):
        return self.default_factory(key)
现在,你想用一点额外的逻辑来充实这一点,例如,如果
self.default\u factory
是None,就像他们在文档中提到的那样。希望这能为你指明正确的方向


这里有一个快速的您可以构建自己的
dict
数据类型。在您的情况下,
\uuuuuu缺少\uuuuu
会有所帮助。如果没有键,
\uuu missing\uu
方法将触发您的自定义工作。下面是一个简单的例子

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
是字典对象的包装器,使您能够轻松地对字典数据类型进行子类化

检查官方文件


这很酷,但是
\uuuuuu缺少\uuuuu
没有设置任何值。也许可以添加对self.setitem(key,self.default\u factory(key))的调用。?很好的团队合作伙伴!在接受之前,等待看是否有人提供了更简单的解决方案。@Julien嗯,使用
setdefault
更简单;)但是说真的,我非常喜欢上面的解决方案。
UserDict
仅在Python 2中是必需的。如果使用Python 3,则可以直接从dict继承
类MyDict(dict):
从集合导入UserDict
对我不起作用(或者
没有名为集合的模块
(而不是
集合
?)或者,
无法导入name UserDict
,但是使用普通的
dict
作为
MyDict
的基础工作得很好!修复了拼写错误,
collection
collections
;]@robru AFAIK,原因是对内置数据类型进行子类化(如
dict
list
)不会调用由用户定义类重写的特殊方法。
collections.UserDict
(或
UserList
)是内置
dict
的包装器,解决了被重写的方法用法。
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}