在Python中为字典创建默认值
我们来看看一个方法,它可以缓存计算出来的结果。
“如果”方法:
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。这个工具就是为了这个目的而设计的。