Задание из Яндекс Практикума по Python, Декораторы
«Задание: Напишите функцию-декоратор, которая сохранит (закеширует) значение декорируемой функции. Если декорируемая функция будет вызвана повторно с теми же параметрами — декоратор должен вернуть сохранённый результат, не выполняя функцию. Подсказка: Создайте словарь и при каждом вызове декоратора сохраняйте в нём аргументы задекорированной функции. При каждом вызове проверяйте, не было ли уже аналогичного вызова. Если был — верните результат прошлого вызова, если не было — верните результат декорируемой функции и одновременно сохраните этот результат в словарь. Ключом для каждой записи словаря может быть аргумент декорируемой функции.» Собственно, код. Написать требуется функцию cache_args, но как ни бьюсь — она работает неверно.
import time from functools import wraps def time_check(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) execution_time = round(time.time() - start_time, 1) print(f'Время выполнения функции : с.') return result return wrapper def cache_args(func): @wraps(func) def wrapper1(*args, **kwargs): result = func(*args, **kwargs) x = [] for t in x: if t == result: return t x = x.append(result) return result return wrapper1 @time_check @cache_args def long_heavy(num): time.sleep(1) return num * 2 print(long_heavy(1)) # Время выполнения функции long_heavy: 1.0 с. # 2 print(long_heavy(1)) # Время выполнения функции long_heavy: 0.0 с. # 2 print(long_heavy(2)) # Время выполнения функции long_heavy: 1.0 с. # 4 print(long_heavy(2)) # Время выполнения функции long_heavy: 0.0 с. # 4 print(long_heavy(2)) # Время выполнения функции long_heavy: 0.0 с. # 4
Отслеживать
2,276 2 2 золотых знака 11 11 серебряных знаков 39 39 бронзовых знаков
задан 27 окт 2021 в 18:03
Crystallice Crystallice
1 1 1 серебряный знак 2 2 бронзовых знака
В подсказке написано создать словарь и хранить там аргументы. А у вас этого нет. У вас везде один аргумент. Вам действительно нужно обрабатывать все арги и кварги? И помнить надо все предыдущие запуски функции, или только предыдущий?
27 окт 2021 в 18:42
@Alpensin x = x.append(result) не дополняет словарь аргументами, получается? Насчет аргов и кваргов не знаю, сделал по аналогии с уже заданной time_check. Судя по заданию, помнить надо все результаты, но если исходить из проверок — то хватит и только предыдущего (и это закодить будет гораздо проще, как мне кажется).
27 окт 2021 в 19:05
@Crystallice Не надо упрощать, там и так проще некуда всё. Вы хотя бы разницу между словарём и списком понимаете? [] — это list , т.е. список. И инициализировать кэш надо вне wrapper1 , иначе при каждом вызове wrapper1 он у вас будет сбрасываться. И func надо вызывать не всегда, а только если результат её вызова с таким же аргументом не закэширован.
27 окт 2021 в 19:08
То есть, я правильно понимаю, что при вызове cache_args будет выполняться только wrapper1, и если словарь определить в cashe_args, то он перезаписываться каждый раз не будет?
27 окт 2021 в 19:39
@Alpensin Ну, почти так. Только словарь в принципе такой
Функция-декоратор, которая кеширует значение декорируемой функции [дубликат]
Есть задание: «Напишите функцию-декоратор, которая сохранит (закеширует) значение декорируемой функции.Если декорируемая функция будет вызвана повторно с теми же параметрами — декоратор должен вернуть сохранённый результат, не выполняя функцию.» И подсказка к заданию: «Создайте словарь и при каждом вызове декоратора сохраняйте в нём аргументы задекорированной функции. При каждом вызове проверяйте, не было ли уже аналогичного вызова. Если был — верните результат прошлого вызова, если не было — верните результат декорируемой функции и одновременно сохраните этот результат в словарь. Ключом для каждой записи словаря может быть аргумент декорируемой функции.» Ну и, собственно, уже готовый код задания, в котором мне нужно дописать функцию def cache_args(func):
import time from functools import wraps def time_check(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) execution_time = round(time.time() - start_time, 1) print(f'Время выполнения функции : с.') return result return wrapper def cache_args(func): # Здесь код декоратора . @time_check @cache_args def long_heavy(num): time.sleep(1) return num * 2 print(long_heavy(1)) # Время выполнения функции long_heavy: 1.0 с. # 2 print(long_heavy(1)) # Время выполнения функции long_heavy: 0.0 с. # 2 print(long_heavy(2)) # Время выполнения функции long_heavy: 1.0 с. # 4 print(long_heavy(2)) # Время выполнения функции long_heavy: 0.0 с. # 4 print(long_heavy(2)) # Время выполнения функции long_heavy: 0.0 с. # 4
Я понимаю, что в данном случае ключ словаря — это аргумент функции: *args. Значение словаря — это значение самой функции. Но как это все написать правильно синтаксически, не знаю.
Кэширование возвращаемых значений в декораторах
Декораторы могут обеспечить хороший механизм для кэширования и запоминания. В качестве примера рассмотрим рекурсивное определение последовательности Фибоначчи:
def fib(num): if num 2: return num return fib(num - 1) + fib(num - 2)
Хотя реализация проста, ее производительность во время выполнения ужасна:
>>> start = time.perf_counter(); fib(20); print('Time run:', time.perf_counter() - start) # 6765 # Time run: 0.005267535000712087 >>> start = time.perf_counter(); fib(30); print('Time run:', time.perf_counter() - start) # 832040 # Time run: 0.1682777839996561
Чтобы вычислить десятое число Фибоначчи, вам нужно вычислить только предыдущие числа Фибоначчи, но эта реализация каким-то образом требует колоссальных 177 вычислений. Ситуация быстро ухудшается для fib(20) — 21891 вычисление и почти 2,7 миллиона вычислений для fib(30) . Это происходит потому, что код продолжает вычислять числа Фибоначчи, которые уже известны.
Обычным решением является реализация чисел Фибоначчи с использованием цикла for . in и таблицы подстановки. Простое кэширование вычислений также делает свое дело:
import functools def cache(func): """Кэш предыдущих вызовов функций""" cache = <> @functools.wraps(func) def wrapper(*args, **kwargs): cache_key = args + tuple(kwargs.items()) if cache_key not in cache: cache[cache_key] = func(*args, **kwargs) return cache[cache_key] return wrapper @cache def fib(num): if num 2: return num return fib(num - 1) + fib(num - 2)
Кэш работает как таблица подстановки, поэтому теперь функция fib() выполняет необходимые вычисления только один раз. Это сразу заметно по времени выполнения функции. Сравните с предыдущим запуском функции, без кэширующего декоратора в начале материала:
>>> import time >>> start = time.perf_counter(); fib(20); print('Time run:', time.perf_counter() - start) # 6765 # Time run: 4.560499928629724e-05 >>> start = time.perf_counter(); fib(30); print('Time run:', time.perf_counter() - start) # 832040 # Time run: 0.000410601000112365
В стандартной библиотеке доступны 2 кэширующих декоратора:
- Декоратор @functools.cache модуля functools представляет собой простой легкий неограниченный кеш функций. Иногда называется «memoization».
- Декоратор @functools.lru_cache кэш LRU. Этот декоратор имеет больше возможностей, чем тот, который представлен для примера.
import functools, time @functools.lru_cache(maxsize=50) def fib(num): if num 2: return num return fib(num - 1) + fib(num - 2) >>> start = time.perf_counter(); fib(30); print('Time run:', time.perf_counter() - start) # 832040 # Time run: 0.00011347100007697009 >>> fib.cache_info() # CacheInfo(hits=28, misses=31, maxsize=50, currsize=31)
Можно использовать метод fib.cache_info() , чтобы увидеть, как работает кэш, так-же можно его настроить, если это необходимо.
В декораторе @functools.lru_cache(maxsize=50) , параметр maxsize указывает сколько последних вызовов кэшируется. Значение по умолчанию равно 128, но вы можете указать maxsize=None для кэширования всех вызовов функций. Однако имейте в виду, что это может вызвать проблемы с памятью.
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Захват аргументов функцией декоратором
- Возврат значений из декорируемой функции
- Атрибут __name__ декорируемой функции
- Шаблон декоратора общего назначения
- Декораторы с аргументами
- Вложенные декораторы
- Кэширование значений в декораторах Python
- Класс как декоратор функции Python
- Декораторы методов класса
- Декораторы классов
- Практические примеры применения декоратора Python
Декоратор для кэширования
Декоратор для кэширования
Задача: Напишите декоратор cached, который будет кэшировать результат вызова функции. Пример.
Написать простой декоратор, используя декоратор wraps, для передачи данных от оригинальной функции
На python Написать простой декоратор, используя декоратор wraps, для передачи данных от.
Как написать декоратор для синхронизации доступа к БД?
Как написать декоратор для синхронизации доступа к БД? Приложение стало использовать.
Написать декоратор для оценки времени вычисления функции
Написать декоратор для оценки времени вычисления функции. Оценить время выполнения функции с его.
Регистрация: 17.11.2020
Сообщений: 1
как говорится, лучше поздно, чем никогда
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def cached(func): cache = {} def a(*args, **kwargs): nonlocal cache if not cache.get(args): g = func(*args, **kwargs) cache[args] = g return g else: return cache[args] return a @cached def fib(n): if n == 1 or n == 2: return 1 else: return fib(n - 1) + fib(n - 2)
3573 / 2174 / 570
Регистрация: 02.09.2015
Сообщений: 5,492
from functools import lru_cache as cached
710 / 349 / 120
Регистрация: 09.12.2020
Сообщений: 919
Arsegg, только хотел написать))
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь
Написать декоратор для оценки времени вычисления функции
имеется код, написать декоратор для оценки времени вычисления функции. Оценить время выполнения.
Напишите декоратор для превращения функции print в генератор html-тегов
# Напишите декоратор для превращения функции print в генератор html-тегов # Декоратор должен.
Декоратор для логированния методов
Реализуйте декоратор, который будет логировать все методы декорируемого класса (кроме магических.
Настройка кэширования для RAID 10
Добрый День. Поделитесь пожалуйста опытом по такому вопросу. Есть SQL сервер на нем RAID 10 из 6.
Использование Dexie для кэширования данных
Приветствую. Пытаюсь использовать Dexie для кеширования данных на стороне браузера. Проблема в.
Создать метод для считывания строк из TextBox (патерн декоратор) для класса Stream
Здравствуйте, нужно создать метод для считывания строки из TextBox (патерн декоратор) для класса.
Или воспользуйтесь поиском по форуму: