Вызов lru_cache из functools
Известно, что в Python синтаксис:
@decorator
def function():
return ...
аналогичен:
def function():
return ...
function = decorator(function)
Но когда я попробовал реализовать подобное поведение с lru_cache из functools, он не сработал. Посмотрев повнимательнее, я увидел, что в сигнатуре вообще нет функции, которая принимается.
Теперь прошу объяснения, а каким образом мне вызвать lru_cache без использования спец. синтаксиса @ в Python?
Ответы (3 шт):
Пример:
In [496]: def f(i):
...: return i**2
...:
In [497]: lru_cache()(f)(3)
Out[497]: 9
In [498]: lru_cache()(f)(4)
Out[498]: 16
Пояснение:
lru_cache возвращает функцию декоратор, которая ожидает на вход вашу функцию, которой в свою очередь нужно передать аргументы.
Нет ни каких проблем, не понимаю, почему для вас «не сработало», на мой комментарий вы не ответили:
from functools import lru_cache
def f(x):
return x * x
f = lru_cache(f) # вместо @
for i in (1, 1, 1, 1, 2, 2):
f(i)
print(f.cache_info())
Вывод:
CacheInfo(hits=4, misses=2, maxsize=128, currsize=2)
Ну в общем-то понятно, почему у вас "не работает", хотя другие ответы на ваш вопрос тоже правильные.
def fib(n):
return 1 if n == 0 or n == 1 else fib(n-1) + fib(n-2)
Если вы обернёте функцию fib в декоратор, то имя fib получит кэшированная версия функции, поэтому кэшироваться будет как основной вызов функции fib, так и рекурсивные вызовы fib из самой себя.
А вот в случае, если вы вручную обернёте функцию fib в lru_cache и вызовете эту обёртку, то исходная функция fib так и останется обычной, не кэшированной. И все рекурсивные вызовы будут к обычной версии fib, от такого кэширования толку не будет, конечно.
cached_fib = lru_cache()(fib)
cached_fib(30)
print(cached_fib.cache_info())
Кэшированная функция вызвалась только один раз:
CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)
Но! Это же питон. Вы можете присвоить кэшированную версию обратно в название исходной функции и всё будет кэшироваться:
fib = lru_cache()(fib)
fib(30)
print(fib.cache_info())
Кэш работает, потому что fib теперь кэшированная:
CacheInfo(hits=28, misses=31, maxsize=128, currsize=31)
Итак, по идее ваш код изначально должен был сработать с кэшированием, просто вы не нашли правильную форму вызова декоратора вручную.