• en
  • Language: ru
  • Documentation version: latest

26. Кэширование функций

Кэширование функций позволяет нам кэшировать возвращаемые значения функции в зависимости от аргументов. Это может сэкономить время, когда функция, связанная с вводом/выводом, периодически вызывается с одними и теми же аргументами. До Python 3.2 нам приходилось писать собственную реализацию. В Python 3.2+ есть декоратор lru_cache, который позволяет нам быстро кэшировать и снимать кэш с возвращаемых значений функции.

Давайте посмотрим, как мы можем использовать его в Python 3.2+ и предшествующих ему версиях.

26.1. Python 3.2+

Давайте реализуем калькулятор Фибоначчи и используем 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)])
# Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Аргумент maxsize говорит lru_cache о том, сколько последних возвращенных значений нужно кэшировать.

Мы также можем легко снять кэширование возвращаемых значений, используя:

fib.cache_clear()

26.2. Python 2+

Есть несколько способов добиться того же эффекта. Вы можете создать любой тип механизма кэширования. Это полностью зависит от ваших потребностей. Вот типовой кэш:

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 не будет кэшировать нехешируемые типы (dict, списки и т.д…), а только неизменяемые типы. Имейте это в виду при использовании.

Here - прекрасная статья от Caktus Group, в которой они поймали ошибку в Django, возникшую из-за lru_cache. Это интересное чтение. Ознакомьтесь с ней.