我在撰写斐波纳契函数时遇到过这个问题。为了更快,我使用名为cache的字典来存储已经计算过的数字。所以我写了
def fib(n, cache=None):
if not cache:
cache = {}
if n in cache:
return cache[n]
if n==0 or n==1:
return 1
else:
cache[n] = fib(n-1, cache) + fib(n-2, cache)
return cache[n]
def fib_run(n):
start = time.time()
fib(n)
end = time.time()
print("fib_run cost: {}".format(end-start))
我调用fib_run(30)
,输出为fib_run cost: 0.8419640064239502
,它与没有缓存的函数一样慢。
但是当我在函数if not cache:
中将if cache is None:
更改为fib2
时,它的工作速度会更快。
def fib2(n, cache=None):
if cache is None:
cache = {}
if n in cache:
return cache[n]
if n==0 or n==1:
return 1
else:
cache[n] = fib2(n-1, cache) + fib2(n-2, cache)
return cache[n]
def fib2_run(n):
start = time.time()
fib2(n)
end = time.time()
print("fib_run cost: {}".format(end-start))
>>> fib2_run(30)
fib2_run cost: 2.6226043701171875e-05
我想知道为什么两种方法之间存在如此大的差异(我认为它们在早期就是一样的)。谢谢。
答案 0 :(得分:1)
这里的问题不是is None
vs not cache
的效果,而是if cache is None
仅True
在第一次调用期间的表现即使fib2
if not cache
True
,cache == {}
fib
为False
。 '空'集合评估为not
因此True
空集合将为>>> not {}
True
:
{}
即使在cache
已经等于{}
的情况下,您也要做额外的工作(将缓存分配给__len__
)。< / p>
一般来说,这些操作在性能上非常相似,一个是简单的身份检查,另一个是基于值的boolness(对于词典,如果我和foldLeft
,则基于Set
的结果#39;我没弄错。)
答案 1 :(得分:0)
在第一种情况下,缓存始终为空!难怪你得到与没有缓存的功能相同的时间。所有你需要的是一个打印,看看会发生什么。
if not cache:
#if cache is None:
print(n, "No cache!")
cache = {}
如上所述,空集合评估为false。在递归调用中,if not cache
始终为true,您创建一个新的dict,您在下面发送一个级别,再次评估为false,依此类推。缓存中从不存在任何条目。
(如上所述,即使在缓存已经等于{}的情况下做额外的工作也是一次性操作。不应该为更大的n花费任何东西