为什么python斐波那契序列循环比递归慢?

为什么python斐波那契序列循环比递归慢?,python,python-3.x,memoization,timeit,Python,Python 3.x,Memoization,Timeit,下面是著名的斐波那契序列示例 # test.py import sys sys.setrecursionlimit(20000) def fib_loop(n): if n <= 1: return n fn, fnm1 = 1, 0 for _ in range(2, n+1): fn, fnm1 = fn + fnm1, fn return fn def fib_recursion(n, memo={}): i

下面是著名的斐波那契序列示例

# test.py
import sys
sys.setrecursionlimit(20000)

def fib_loop(n):
    if n <= 1:
        return n
    fn, fnm1 = 1, 0
    for _ in range(2, n+1):
        fn, fnm1 = fn + fnm1, fn
    return fn

def fib_recursion(n, memo={}):
    if n <= 1:
        return n
    if n not in memo:
        memo[n] = fib_recursion(n-1, memo) + fib_recursion(n-2, memo)
    return memo[n]
我不知道为什么。有人能帮我吗?

因为你正在记录你的结果。你在每一次迭代中都会用到备忘录。所以它第一次运行时速度很慢。在其他每一项活动中,它都是一个简单的dict查找

如果您使用
number=1
,因此它只运行一次,您将看到第一次调用实际上较慢

>>> import sys
>>> sys.setrecursionlimit(20000)
>>>
>>> def fib_loop(n):
...     if n <= 1:
...         return n
...     fn, fnm1 = 1, 0
...     for _ in range(2, n+1):
...         fn, fnm1 = fn + fnm1, fn
...     return fn
...
>>> def fib_recursion(n, memo={}):
...     if n <= 1:
...         return n
...     if n not in memo:
...         memo[n] = fib_recursion(n-1, memo) + fib_recursion(n-2, memo)
...     return memo[n]
...
>>> import timeit
>>> timeit.timeit("fib_loop(1000)", setup="from __main__ import fib_loop", number=1)
9.027599999456015e-05
>>> timeit.timeit("fib_recursion(1000)", setup="from __main__ import fib_recursion", number=1)
0.0016194200000114733

删除
备忘录
并检查差异,然后…如果您没有提供任何数字来计时,代码将在
number=1000000次执行中取平均值()。您可以对结果进行记忆,因此对于9999999次尝试,它只是对(一次)生成的dict进行O(1)查找,而循环必须重新计算1000000次数字。我不知道timeit函数再次重用
memo
变量。它不是一个局部变量吗?@gulinproject变量的范围是无关的,它每次都在重复使用同一个对象。不管怎样,这通常就是记忆的工作方式,否则它将如何工作?哇,这真是令人惊讶。我不知道默认值每次都会被共享和重用…@GulimProject请参阅-dict在函数定义时创建一次,并一直保存到使用python重新启动文件为止。在为函数提供list或dict“defaults”时,这是一个常见错误,因此,如果您不希望这种行为(除非您想要,否则您可以按原样使用它),您通常会在函数中提供None作为默认值,并在函数中执行“defaultlist=defaultlist或[]”@juanpa.arrivillaga不,即使不需要,它也会工作,因为我在递归调用中将
memo
作为参数传递。有趣的是,即使我没有通过,函数仍然会记住结果。
>>> import sys
>>> sys.setrecursionlimit(20000)
>>>
>>> def fib_loop(n):
...     if n <= 1:
...         return n
...     fn, fnm1 = 1, 0
...     for _ in range(2, n+1):
...         fn, fnm1 = fn + fnm1, fn
...     return fn
...
>>> def fib_recursion(n, memo={}):
...     if n <= 1:
...         return n
...     if n not in memo:
...         memo[n] = fib_recursion(n-1, memo) + fib_recursion(n-2, memo)
...     return memo[n]
...
>>> import timeit
>>> timeit.timeit("fib_loop(1000)", setup="from __main__ import fib_loop", number=1)
9.027599999456015e-05
>>> timeit.timeit("fib_recursion(1000)", setup="from __main__ import fib_recursion", number=1)
0.0016194200000114733
>>> timeit.timeit("fib_recursion(1000, {})", setup="from __main__ import fib_recursion", number=1000)
0.38679519899999093
>>> timeit.timeit("fib_loop(1000)", setup="from __main__ import fib_loop", number=1000)
0.07079556799999409