- 6 Python декораторов, которые значительно упростят ваш код
- 1. @lru_cache: Ускоряем программы кэшированием
- 2. @total_ordering: Добавляем недостающие методы сравнения
- 3. @contextmanager: Кастомный менеджер контекстов
- 4. @property: Настраиваем геттеры и сеттеры для классов
- 6. @atexit.register: Объявляем функцию которая вызывается при выходе из программы
- Как работать с кэшированием данных в Python
- Что такое кэширование данных?
- Встроенный декоратор functools.lru_cache
- Кэширование с использованием внешних хранилищ
- Заключение
- Как использовать Python для работы с кэшем
- Использование библиотеки cachetools
- Использование декораторов для кэширования
- Работа с кэшем в веб-приложениях
- Flask
- Django
6 Python декораторов, которые значительно упростят ваш код
Лучшая функция Python, которая применяет эту философию из «дзен Python», — это декоратор.
Декораторы могут помочь вам писать меньше кода для реализации сложной логики и повторно использовать его повсюду.
Более того, существует множество замечательных встроенных декораторов Python, которые значительно облегчают нам жизнь, поскольку мы можем просто использовать одну строчку кода для добавления сложных функций к существующим функциям или классам.
Болтать не буду. Давайте посмотрим на отобранные мной 6 декораторов, которые покажут вам, насколько элегантен Python.
1. @lru_cache: Ускоряем программы кэшированием
Самый простой способ ускорить работу функций Python с помощью трюков кэширования — использовать декоратор @lru_cache.
Этот декоратор можно использовать для кэширования результатов функции, так что последующие вызовы функции с теми же аргументами не будут выполняться снова.
Это особенно полезно для функций, которые требуют больших вычислительных затрат или часто вызываются с одними и теми же аргументами.
Рассмотрим интуитивно понятный пример:
import time def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) start_time = time.perf_counter() print(fibonacci(30)) end_time = time.perf_counter() print(f"The execution time: seconds") # The execution time: 0.18129450 seconds
Приведенная выше программа вычисляет N-ое число Фибоначчи с помощью функции Python. Это занимает много времени, поскольку при вычислении fibonacci(30) многие предыдущие числа Фибоначчи будут вычисляться много раз в процессе рекурсии.
Теперь давайте ускорим этот процесс с помощью декоратора @lru_cache:
from functools import lru_cache import time @lru_cache(maxsize=None) def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) start_time = time.perf_counter() print(fibonacci(30)) end_time = time.perf_counter() print(f"The execution time: seconds") # The execution time: 0.00002990 seconds
Как видно из приведенного выше кода, после использования декоратора @lru_cache мы можем получить тот же результат за 0,00002990 секунды, что намного быстрее, чем предыдущие 0,18129450 секунды.
Декоратор @lru_cache имеет параметр maxsize, который определяет максимальное количество результатов для хранения в кэше. Когда кэш заполнен и необходимо сохранить новый результат, наименее использованный результат вытесняется из кэша, чтобы освободить место для нового. Это называется стратегией наименее использованного результата (LRU).
По умолчанию maxsize установлен на 128. Если оно установлено в None, как в нашем примере, функции LRU отключены, и кэш может расти без ограничений.
2. @total_ordering: Добавляем недостающие методы сравнения
Декоратор @total_ordering из модуля functools используется для генерации недостающих методов сравнения для класса Python на основе тех, которые определены.
from functools import total_ordering @total_ordering class Student: def __init__(self, name, grade): self.name = name self.grade = grade def __eq__(self, other): return self.grade == other.grade def __lt__(self, other): return self.grade < other.grade student1 = Student("Alice", 85) student2 = Student("Bob", 75) student3 = Student("Charlie", 85) print(student1 < student2) # False print(student1 >student2) # True print(student1 == student3) # True print(student1 = student2) # True
Как видно из приведенного выше кода, в классе Student нет определений для методов ge, gt и le. Однако благодаря декоратору @total_ordering результаты наших сравнений между различными экземплярами будут правильными.
Преимущества этого декоратора очевидны:
- Он может сделать ваш код чище и сэкономить ваше время. Поскольку вам не нужно писать все методы сравнения.
- Некоторые старые классы могут не определять достаточно методов сравнения. Безопаснее добавить к нему декоратор @total_ordering для дальнейшего использования.
3. @contextmanager: Кастомный менеджер контекстов
В Python есть механизм менеджмента контекста, который поможет вам правильно управлять ресурсами.
В основном нам нужно просто использовать операторы with:
with open("test.txt",'w') as f: f.write("Yang is writing!")
Как показано в приведенном выше коде, мы можем открыть файл с помощью оператора with, чтобы он был закрыт автоматически после записи. Нам не нужно явно вызывать функцию f.close(), чтобы закрыть файл.
Иногда нам нужно определить индивидуальный менеджер контекста для каких-то особых требований. В этом случае декоратор @contextmanager - наш друг.
Например, следующий код реализует простой настраиваемый контекстный менеджер, который может выводить соответствующую информацию при открытии или закрытии файла.
from contextlib import contextmanager @contextmanager def file_manager(filename, mode): print("The file is opening. ") file = open(filename,mode) yield file print("The file is closing. ") file.close() with file_manager('test.txt', 'w') as f: f.write('Yang is writing!') # The file is opening. # The file is closing.
4. @property: Настраиваем геттеры и сеттеры для классов
Геттеры и сеттеры - важные понятия в объектно-ориентированном программировании (ООП).
Для каждой переменной экземпляра класса метод getter возвращает ее значение, а метод setter устанавливает или обновляет ее значение. Учитывая это, геттеры и сеттеры также известны как аксессоры и мутаторы, соответственно.
Они используются для защиты данных от прямого и неожиданного доступа или изменения.
Различные языки ООП имеют разные механизмы для определения геттеров и сеттеров. В Python мы можем просто использовать декоратор @property.
class Student: def __init__(self): self._score = 0 @property def score(self): return self._score @score.setter def score(self, s): if 0
Как видно из приведенного выше примера, переменная score не может быть установлена как 999, что является бессмысленным числом. Потому что мы ограничили ее допустимый диапазон внутри функции сеттера с помощью декоратора @property.
Без сомнения, добавление этого сеттера может успешно избежать неожиданных ошибок или результатов.
5. @cached_property: Кешируем результат функции как атрибут
В Python 3.8 в модуле functools появился новый мощный декоратор - @cached_property. Он может превратить метод класса в свойство, значение которого вычисляется один раз, а затем кэшируется как обычный атрибут на протяжении всего существования экземпляра.
from functools import cached_property class Circle: def __init__(self, radius): self.radius = radius @cached_property def area(self): return 3.14 * self.radius ** 2 circle = Circle(10) print(circle.area) # prints 314.0 print(circle.area) # returns the cached result (314.0) directly
В приведенном выше коде мы оптимизировали метод area через свойство @cached_property. Таким образом, нет повторных вычислений для circle.area одного и того же неизменного экземпляра.
6. @atexit.register: Объявляем функцию которая вызывается при выходе из программы
Декоратор @register из модуля atexit может позволить нам выполнить функцию при завершении работы интерпретатора Python.
Этот декоратор очень полезен для выполнения финальных задач, таких как освобождение ресурсов или просто прощание! 👋
import atexit @atexit.register def goodbye(): print("Bye bye!") print("Hello Yang!")
Еще больше примеров использования Python и Machine Learning в современных сервисах можно посмотреть в моем телеграм канале. Я пишу про разработку, ML, стартапы и релокацию в UK для IT специалистов.
Как работать с кэшированием данных в Python
Узнайте, как оптимизировать работу Python-приложений с помощью кэширования данных, используя встроенный декоратор и внешние хранилища.
Кэширование данных — это важный аспект в разработке приложений, так как это позволяет оптимизировать процесс загрузки и обработки информации. В этой статье мы разберем основные принципы кэширования данных в Python и покажем примеры его использования.
Что такое кэширование данных?
Кэширование данных — это процесс хранения результатов выполнения функций и запросов во временном хранилище (кэше) с целью ускорения повторного обращения к ним. Вместо того чтобы заново выполнять те же операции, можно просто получить результат из кэша, что существенно экономит время и ресурсы.
Встроенный декоратор functools.lru_cache
Python предоставляет встроенный декоратор functools.lru_cache , который позволяет легко кэшировать результаты функций. LRU (Least Recently Used) кэш — это кэш с ограниченным размером, который автоматически удаляет наименее недавно использованные элементы при необходимости освободить место для новых данных.
Пример использования functools.lru_cache :
import functools @functools.lru_cache(maxsize=100) def expensive_function(arg1, arg2): # Здесь выполняется какая-то дорогостоящая операция result = arg1 + arg2 return result # Вызов функции result = expensive_function(1, 2)
В этом примере результаты expensive_function будут кэшироваться и сохраняться в LRU-кэше размером до 100 элементов.
Кэширование с использованием внешних хранилищ
В некоторых случаях может потребоваться кэширование данных с использованием внешних хранилищ, таких как Redis или Memcached. Это особенно актуально при работе с веб-приложениями и распределенными системами.
Пример кэширования данных с использованием Redis:
import redis cache = redis.Redis(host='localhost', port=6379) def cache_data(key, data, ttl=3600): cache.setex(key, ttl, data) def get_cached_data(key): return cache.get(key) # Кэширование данных cache_data('my_key', 'my_data') # Получение данных из кэша result = get_cached_data('my_key')
В этом примере мы используем библиотеку redis для работы с кэшем Redis. Функции cache_data и get_cached_data позволяют сохранять и получать данные из кэша соответственно.
Заключение
Кэширование данных является полезным инструментом для оптимизации работы приложений и снижения нагрузки на серверы. В Python существует несколько способов реализации кэширования, включая встроенный декоратор functools.lru_cache и использование внешних хранилищ, таких как Redis или Memcached. Экспериментируйте с различными подходами и выбирайте тот, который наиболее подходит для вашего проекта. 😊
Как использовать Python для работы с кэшем
Узнайте, как работать с кэшем в Python с помощью библиотеки cachetools, декораторов и в веб-приложениях Flask и Django.
Кэширование — это процесс хранения данных во временном хранилище, чтобы быстрее получать доступ к ним в будущем. Python предоставляет несколько способов работы с кэшем, и в этой статье мы обсудим наиболее популярные из них.
Использование библиотеки cachetools
Библиотека cachetools предоставляет различные алгоритмы кэширования, такие как Least Recently Used (LRU), Most Recently Used (MRU) и другие. Для начала установите cachetools с помощью pip :
Теперь вы можете использовать кэш LRU следующим образом:
import cachetools cache = cachetools.LRUCache(maxsize=100) def get_data(key): # Здесь происходит получение данных из источника pass def cached_get_data(key): if key not in cache: cacheДекоратор для кэширования python = get_data(key) return cacheДекоратор для кэширования python
В этом примере мы создали кэш с максимальным размером 100 элементов. Функция cached_get_data сначала проверяет, есть ли данные в кэше, и если нет, загружает их и сохраняет в кэше перед возвратом.
Использование декораторов для кэширования
Python также предоставляет возможность использовать декораторы для кэширования результатов функций. Вот пример использования декоратора lru_cache из стандартной библиотеки functools :
from functools import lru_cache @lru_cache(maxsize=100) def get_data(key): # Здесь происходит получение данных из источника pass result = get_data("some_key")
В этом случае кэширование автоматически применяется к функции get_data , и результаты будут сохраняться в кэше LRU с максимальным размером 100 элементов.
😉 Учтите, что декоратор lru_cache работает только с hashable (хешируемыми) аргументами функции.
Работа с кэшем в веб-приложениях
В веб-приложениях на Python, таких как Flask или Django, кэширование также играет важную роль. Обе библиотеки предоставляют свои собственные механизмы кэширования.
Flask
Во Flask кэширование можно настроить с помощью расширения Flask-Caching . Установите его с помощью pip :
Теперь вы можете создать кэш и использовать его в вашем приложении:
from flask import Flask from flask_caching import Cache app = Flask(__name__) cache = Cache(app, config=) @app.route('/some-data') @cache.cached(timeout=60) def get_some_data(): # Здесь происходит получение данных из источника pass
В этом примере мы использовали декоратор @cache.cached с таймаутом 60 секунд для кэширования результатов функции get_some_data .
Django
Django предоставляет встроенную поддержку кэширования. Настройте кэш в файле settings.py вашего проекта:
Теперь вы можете использовать кэш в своих представлениях:
from django.core.cache import cache def get_data(request): data = cache.get('some_key') if data is None: data = # Здесь происходит получение данных из источника cache.set('some_key', data, 60) return data
В этом примере мы использовали кэш LocMemCache и установили таймаут в 60 секунд.
В заключение, кэширование — это важный аспект работы с данными в Python. Использование кэша помогает ускорить доступ к данным и уменьшить нагрузку на источники данных. Надеемся, что эти примеры помогут вам начать работу с кэшированием в Python.