Рубрики
Без рубрики

Мемозионные функции в Python с Functools.lru_cache

«Мемоназированная функция« запоминает »результаты, соответствующие некоторому набору определенных входов». (Из Wik … с меткой Python функционально.

«Мемоназированная функция« запоминает »результаты, соответствующие некоторому набору определенных входов». (Из Статья воспоминания Википедии ). Я думаю о воспоминании как внутренний умный кэш. Вометошенная функция кэширует результаты, зависящие от аргументов.

Python Обеспечивает удобный и высокопроизводительный способ взаимомешения функций через functools.lru_cache декоратор . Не стесняйтесь вырвать на Lru (наименее недавно использованный) алгоритм это используется здесь.

У вас есть «чистые» функции, которые не имеют побочных эффектов? Другими словами, когда он многократно называется с теми же аргументами, функция будет и должна вернуть точно такие же результаты? Кроме того, функция вычисляется «дорого» или ждет операций ввода/вывода?

Если это так, эта функция может быть изменена с lru_cache Отказ

Набок Примечание. Для эффективных метеоризований аргументы должны быть “Hashable” , такие как строки и цифры, не диктовы или списки. Более конкретно, каждый аргумент должен иметь А __hash__ Метод Отказ

Возьмите следующую функцию:

def expensive(filepath):
    return hashlib.sha512(filepath.read_bytes()).hexdigest()

В большом файле, который никогда не меняется, эта дорогостоящая операция не должна работать не раз. Таким образом, эта функция является достойным кандидатом на воспоминание с functools.lru_cache Отказ Вот более полное исполнение:

import functools
import hashlib
import os
import pathlib
import time


@functools.lru_cache()
def expensive(filepath):
    return hashlib.sha512(filepath.read_bytes()).hexdigest()


def run():
    file_path = pathlib.Path("bigfile.txt")
    if not file_path.exists():
        file_path.write_bytes(os.urandom(1024 ** 3))

    print(f"Start: {time.strftime('%X')}")
    print(expensive(file_path))
    print(f"End: {time.strftime('%X')}\n")

    print(f"Start memoized: {time.strftime('%X')}")
    print(expensive(file_path))
    print(f"End memoized: {time.strftime('%X')}")


if __name__ == "__main__":
    run()

Сохраните этот файл как lru_test.py. И вы должны быть в состоянии выполнить этот файл с чем-то вроде:

python lru_test.py

Это создаст файл 1 ГБ с именем Bigfile.txt И хэш это «дважды», показываю вас до и после временных метров. Конечно, это только это включить его в первый раз. Второй раз, это читает кеш, связанный с этим именем файла. Он возвращает памятку, кэшированную ценность и не нужно переводить.

Очистить кеш

дорогой () Функция выше не чистая, по моим выбору, поэтому мы можем продемонстрировать еще одну особенность lru_cache Отказ Потенциально файл может измениться на диске.

Что вы делаете, если вы хотите, чтобы преимущества производительности lru_cache. Но также хочется решить, по случаю, что кэшированные ценности нельзя доверять?

Выполнить cache_clear () на функцию, которая была украшена. Полный пример, чтобы продемонстрировать точку:

import functools
import hashlib
import os
import pathlib
import time


@functools.lru_cache()
def expensive(filepath):
    return hashlib.sha512(filepath.read_bytes()).hexdigest()


def run():
    file_path = pathlib.Path("bigfile.txt")
    if not file_path.exists():
        file_path.write_bytes(os.urandom(1024 ** 3))

    print(f"Start: {time.strftime('%X')}")
    print(expensive(file_path))
    print(f"End: {time.strftime('%X')}\n")

    print(f"Start memoized: {time.strftime('%X')}")
    print(expensive(file_path))
    print(f"End memoized: {time.strftime('%X')}\n")

    expensive.cache_clear()

    print(f"Start cleared: {time.strftime('%X')}")
    print(expensive(file_path))
    print(f"End cleared: {time.strftime('%X')}")


if __name__ == "__main__":
    run()

Запуск этого скрипта снова должен продемонстрировать это, один раз cache_clear () называется, функция должна полностью выполняться снова. Он имеет «забытые» ценности, ранее вычисленные.

Боковая заметка: в Python 3.8, а затем вам не нужны скобки после @lru_cache декоратор. Это работает нормально:

@functools.lru_cache
def expensive(filepath):
    return hashlib.sha512(filepath.read_bytes()).hexdigest()

Я надеюсь, что это поможет вам быть полностью функциональным.

Оригинал: “https://dev.to/bowmanjd/memoized-functions-in-python-with-functools-lrucache-5d8j”