【发布时间】:2018-02-01 15:30:46
【问题描述】:
我正在使用斐波那契函数进行记忆装饰器练习。当输入变大时,memoized 函数应该会更快,因为它从字典中返回结果,而不是再次计算结果。
我正在使用timeit.timeit() 来测量函数的执行时间,其中memoized on vs off。
我得到的结果与我的预期完全相反。没有装饰器的执行运行得更快。
# memorized decorator for fibonacci series
def mem_fib(f):
def wrapper(n):
wrapper.d = {} # create the attr member of THIS wrapper
if n in wrapper.d:
return wrapper.d[n]
wrapper.d[n] = f(n) # save f() return in a dict
return wrapper.d[n]
return wrapper
@mem_fib
def fibonacci(n):
assert n >= 0
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
我正在 PyCharm python 的控制台上运行命令。
@with 装饰器
>>> print(timeit.timeit('decorators.fibonacci(7)', setup='import decorators'))
19.6940833939
>>> print(timeit.timeit('decorators.fibonacci(10)', setup='import decorators'))
85.7157191166
没有装饰器
>>> print(timeit.timeit('decorators.fibonacci(7)', setup='import decorators'))
5.10131571594
>>> print(timeit.timeit('decorators.fibonacci(10)', setup='import decorators'))
21.9784012801
我多次运行timeit,我只是放一个输出来总结它。我错过了什么?
谢谢
更新:感谢丹尼尔的回答,我发现了我的错误。我将字典创建移到了包装器之外,结果要好得多。
>>> print(timeit.timeit('decorators.fibonacci(10)', setup='import decorators'))
0.248986574759
【问题讨论】:
-
您是否已经厌倦了追求更大的价值?我的猜测是,对于 7 和 10,memoization 引入的少量开销大于实际计算的成本。我想对于 fibbonacci(100) 它可能会产生预期的结果。
-
会不会是因为你的断言声明?作为旁注,您不需要最后的 pass 语句。您可以检查负 n 并引发错误,然后检查基本情况并返回。如果两个检查都失败了,一定是递归的情况,因此不需要使用else。
-
麦这个小改动让代码更容易阅读,感谢注释