为什么python语句`如果某些东西是None`的工作比`if not something'快得多?

时间:2017-04-05 08:03:45

标签: python performance python-3.x

我在撰写斐波纳契函数时遇到过这个问题。为了更快,我使用名为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

我想知道为什么两种方法之间存在如此大的差异(我认为它们在早期就是一样的)。谢谢。

2 个答案:

答案 0 :(得分:1)

这里的问题不是is None vs not cache的效果,而是if cache is NoneTrue在第一次调用期间的表现即使fib2 if not cache Truecache == {} fibFalse。 '空'集合评估为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花费任何东西