在Python字典中获取和设置一个值的最佳方法是什么?

18

我使用一个 dict 作为短期缓存。我想从字典中获取一个值,如果字典中没有这个键,则设置它,例如:

val = cache.get('the-key', calculate_value('the-key'))
cache['the-key'] = val

如果'the-key'已经存在于cache中,第二行代码就没必要了。有没有更好、更短、更表达清晰的写法?


4
请注意,这个代码片段会计算默认值,无论它是否在字典中。 - Cat Plus Plus
你当然是正确的。在这种特定情况下,对我来说并不重要,因为“calculate_value”的结果是惰性评估的。 - Benjamin Wohlwend
8个回答

24

可读性很重要!

if 'the-key' not in cache:
    cache['the-key'] = calculate_value('the-key')
val = cache['the-key']

如果您确实喜欢一行代码:

val = cache['the-key'] if 'the-key' in cache else cache.setdefault('the-key', calculate_value('the-key'))

另一种选择是在缓存类中定义 __missing__

class Cache(dict):
    def __missing__(self, key):
        return self.setdefault(key, calculate_value(key))

2
由于此答案并不总是计算缺失值并且提供更多解决方案,因此它应该被接受为答案。 - Lars Blumberg

22

是的,使用以下代码:

val = cache.setdefault('the-key', calculate_value('the-key'))

在shell中的一个例子:

>>> cache = {'a': 1, 'b': 2}
>>> cache.setdefault('a', 0)
1
>>> cache.setdefault('b', 0)
2
>>> cache.setdefault('c', 0)
0
>>> cache
{'a': 1, 'c': 0, 'b': 2}

请参考:http://docs.python.org/release/2.5.2/lib/typesmapping.html


12
无论如何都会计算calculate_value('the-key') - eumiro
3
@eumiro,没错。糟糕的是我甚至没有注意到 - 根据calculate_value可能会很昂贵。 - Daren Thomas

6

这是最具Python风格的答案。 - georg

4

使用以下方法:

cache.setdefault('the-key',calculate_value('the-key'))

如果calculate_value的计算成本不高,那么使用它是很好的,因为它将每次被求值。但是,如果你需要从数据库中读取、打开文件或网络连接,或者进行任何“昂贵”的操作,则应使用以下结构:

try:
    val = cache['the-key']
except KeyError:
    val = calculate_value('the-key')
    cache['the-key'] = val

异常处理有时也会比较耗费资源。根据代码被调用的频率以及你期望缓存未命中的频率,使用 if-then 块可能会更快一些。 - Felix

2
你也可以使用defaultdict来做类似的事情:
>>> from collections import defaultdict
>>> d = defaultdict(int) # will default values to 0
>>> d["a"] = 1
>>> d["a"]
1
>>> d["b"]
0
>>>

您可以通过提供自己的工厂函数和itertools.repeat来分配任何默认值:

>>> from itertools import repeat
>>> def constant_factory(value):
...    return repeat(value).next
...
>>> default_value = "default"
>>> d = defaultdict(constant_factory(default_value))
>>> d["a"]
'default'
>>> d["b"] = 5
>>> d["b"]
5
>>> d.keys()
['a', 'b']

defaultdict的问题在于它的工厂函数对键值一无所知。 - georg
我理解如果你有不同键的默认值,那么这是必要的,但如果你只需要所有键的相同默认值,defaultdict就足够了。 - monkut

2

1

使用setdefault方法,

如果键已经不存在,则setdefault会使用第二个参数中提供的value创建新键,如果键已经存在,则返回该键的值。

val = cache.setdefault('the-key',value)

3
无论如何,这将计算calculate_value('the-key') - eumiro

0
使用get来提取值或获取None
Noneor组合使用,可以让您链接另一个操作(setdefault)。
def get_or_add(cache, key, value_factory):
    return cache.get(key) or cache.setdefault(key, value_factory())

用法: 为了使它变成惰性的,该方法期望将函数作为第三个参数。

get_or_add(cache, 'the-key', lambda: calculate_value('the-key'))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接