在Python中为字典创建默认值

14 投票
3 回答
19110 浏览
提问于 2025-04-16 07:53

我们来看看一个方法,它可以缓存计算出来的结果。

“如果”方法

def calculate1(input_values):
    if input_values not in calculate1.cache.keys():
        # do some calculation
        result = input_values
        calculate1.cache[input_values] = result
    return calculate1.cache[input_values]
calculate1.cache = {}

“除了”方法

def calculate2(input_values):
    try:
       return calculate2.cache[input_values]
    except AttributeError:
       calculate2.cache = {}
    except KeyError:
       pass
    # do some calculation
    result = input_values
    calculate2.cache[input_values] = result
    return result

“获取/是否有”方法

def calculate3(input_values):

    if not hasattr(calculate3, cache):
        calculate3.cache = {}

    result = calculate3.cache.get(input_values)
    if not result:
        # do some calculation
        result = input_values
        calculate3.cache[input_values] = result
    return result

还有其他(更快)的方法吗?哪种方法最符合 Python 风格?你会选择哪一种?

注意:这些方法在速度上是有区别的:

calculate = calculateX # depening on test run
for i in xrange(10000):
    calculate(datetime.utcnow())

结果 time python test.py

calculate1: 0m9.579s
calculate2: 0m0.130s
calculate3: 0m0.095s

3 个回答

3

如果你想要做记忆化处理,最好使用一个叫做 Memoize 的类和装饰器。

class Memoize(object):
    def __init__(self, func):
        self.func = func
        self.cache = {}

    def __call__(self, *args):
        if args not in self.cache:
            self.cache[args] = self.func(*args)
        return self.cache[args]

现在定义一个需要记忆化的函数,比如一个增强键值的函数,它会对一个字符串进行大约 100,000 次 md5 哈希计算:

import md5

def one_md5(init_str):
    return md5.md5(init_str).hexdigest()

@Memoize
def repeat_md5(cur_str, num=1000000, salt='aeb4f89a2'):
    for i in xrange(num):
        cur_str = one_md5(cur_str+salt)
    return cur_str

@Memoize 这个函数装饰器就相当于先定义了这个函数,然后再写 repeat_md5 = Memoize(repeat_md5)。第一次用特定的参数调用这个函数时,大约需要一秒钟来计算;而下次调用时,它几乎是瞬间完成,因为它直接从缓存中读取结果。

至于记忆化的方法,只要你没有做一些傻事(比如用 if key in some_dict.keys() 而不是 if key in some_dict),就不会有太大的区别。 (第一种方法不好,因为你先从字典生成一个数组,然后再检查这个键是否在里面;而不是直接检查这个键是否在字典中(参见 像个 Python 大师那样编码)。另外,捕获异常的速度自然会比用 if 语句慢(因为你需要先创建一个异常,然后异常处理器再处理它,最后你再捕获它)。

5

当然可以;毕竟这是Python语言。你只需要使用一个叫做 defaultdict 的东西就行了。

25

可以使用 collections.defaultdict。这个工具就是为了这个目的而设计的。

撰写回答