Только будьте осторожны: трюк fib.cache
работает только в том случае, если fib
действительно является именем соответствующего функционального объекта в области, которая активна во время его выполнения (например, когда вы украшаете его, как вы это сделали, вы должны присвойте начальное значение для кэша оболочке декоратора, а не декорированной функции - и, если после этого он будет декорирован, все прекратится).
Это немного хрупко по сравнению со стандартной идиомой запоминания:
def fib(n, _memo={0:1, 1:1}):
if n in _memo:
return _memo[n]
else:
_memo[n] = fib(n-1) + fib(n-2)
return _memo[n]
или эквивалент декоратора. Стандартная идиома также быстрее (хотя и ненамного) - помещая их оба в mem.py под именами fib1 (.cache-trick, без отпечатков и без отделки) и fib2 (моя версия), мы видим ...:
$ python -mtimeit -s'import mem' 'mem.fib1(20)'
1000000 loops, best of 3: 0.754 usec per loop
$ python -mtimeit -s'import mem' 'mem.fib2(20)'
1000000 loops, best of 3: 0.507 usec per loop
Таким образом, стандартная версия экономит около 33% времени, но именно тогда почти все вызовы действительно попадают в кэш напоминаний (который заполняется после первого из этих миллионов циклов) - преимущество в скорости fib2 меньше отсутствует кеш, так как он происходит из-за более высокой скорости доступа к _memo
(локальная переменная) по сравнению с fib.cache
(глобальное имя, fib, а затем его атрибут, кеш), а доступ к кешу преобладает при обращениях к кешу (нет ничего еще ;-) но есть небольшая дополнительная работа (равная для обеих функций) при промахах кэша.
Во всяком случае, не хочу идти дождь на своем параде, но когда вы найдете какую-то новую классную идею, обязательно сравните ее со «старым добрым способом» ведения дел, как с точки зрения «надежности», так и производительности (если вы кешируете, вероятно, вы заботитесь о производительности; -).