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}