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