Кэширование функций позволяет кэшировать возвращаемые значения функций в
зависимости от аргументов. Это может помочь сэкономить время при работе
с вводом/выводом на повторяющихся данных. До Python 3.2 мы должны были бы
написать собственную реализацию. В Python 3.2+ появился декоратор lru_cache
,
который позволяет быстро кэшировать возвращаемые функцией значения.
Давайте посмотрим, как мы можем воспользоваться кэшированием в Python 3.2+ и в более старых версиях.
Реализуем функцию расчета n-ого числа Фибоначчи с использованием lru_cache
:
from functools import lru_cache
@lru_cache(maxsize=32)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
>>> print([fib(n) for n in range(10)])
# Вывод: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Аргумент maxsize
сообщает lru_cache
сколько последних значений
запоминать.
Мы также можем легко очистить кэш:
fib.cache_clear()
В старых версиях языка также есть несколько путей достижения схожего эффекта. Вы можете сами реализовать любой тип кэширования. Это зависит только от ваших потребностей. Вот базовое решение:
from functools import wraps
def memoize(function):
memo = {}
@wraps(function)
def wrapper(*args):
try:
return memo[args]
except KeyError:
rv = function(*args)
memo[args] = rv
return rv
return wrapper
@memoize
def fibonacci(n):
if n < 2: return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(25)
Примечание: memoize
не сможет кэшировать типы данных, которые нельзя хешировать (словари, списки и т.д.). Только объекты неизменяемых типов подлежат кэшированию. Держите это в уме при использовании декоратора.
Отличная статья
от Caktus Group, в которой они рассказывают историю бага в Django, который
появился из-за lru_cache
. Рекомендую к ознакомлению.