Python декораторы
Декораторы - одни из самых часто используемых инструментов в Python
Например , в документации Django вы можете увидеть такой код , где для кеширования вьюхи предлагают использовать декоратор cache_page
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
Тут для кеширования вьюхи my_view предлагается использовать декоратор cache_page , который принимает в качестве единственного аргумента:длительность кэширования, в секундах. Самое крутое , что этот декоратор мы можем использовать и для других вьюх, которые нужно закешировать.
Или возьмем другой пример. В официальной документации FastApI можем увидеть такой код, где используется декоратор для представления.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
Как мы можем видеть, в Python декораторы используется практически везде , так как позволяют эффетивно и изящно добавить дополнительный функционал для функций , без изменения их содержимого.
Допустим у вас есть вьюха в виде функции на Django, которую хотите показывать только для зарегистрированных пользователей. Вы конечно , можете написать код, внутри вьюхи, где проверяется авторизован пользователь или нет или же просто использовать декоратор login_required , который присутствует в Django. Либо же сами написать свой декоратор. Ну а чтобы писать свои декораторы , нужно разобраться , что такое декоратор и как его реализовать. Давайте восполним этот пробел.
Как мы знаем(если не знали, то сделаете вид , что знаете) , в Python все является объектом. Соответственно , и функции являются объектами.
Будучи объектами функции можно сохранять в переменные
def print_hello_world():
print("Hello World!")
#Так как в Python функция является объектом,то мы можем присвоить ее переменной
hello_world = print_hello_world()
или же их можно передавать в качестве аргументов в другую функцию
def print_hello_world():
print("Hello World!")
#Функцию print_hello_world передаем в качестве аргумента в другую функцию
def other_func(print_hello_world):
#вызываем функцию
print_hello_world()
Также мы можем внутри одной функции определить другую функции и возвратить ее в качестве значения:.
>>> def wrapper():
... def inner():
... print("this is inner function")
... return inner
...
>>> #Присваиваем объект функции переменной
>>> my_func = wrapper
>>> my_func
>>> #Вызываем функцию
>>> my_func()
this is inner function
Из вышесказанного следует , что в Python функции являются объектами первого класса
Зная все это мы можем написать наш первый декоратор. Вначале определимся , что будет делать этот декоратор.Допустим , у нас есть функция welcome , которая выводит на экран сообщение "Добро пожаловать!!! Вызов оборачиваемой функции". Напишем декоратор , который позволит выводит сообщения до вызова этой функции и после вызова.
def my_first_decorator(func):
def wrapper():
print("---Эта строка выведется до вызова оборачиваемой функции---")
func()
print("---Эта строка выведется после вызова оборачиваемой функции---")
return wrapper
@my_first_decorator
def welcome():
print("Добро пожаловать!!! Вызов оборачиваемой функции")
welcome()
Мы написали наш декоратор my_first_decorator, который в качестве аргумента принимает функцию func, который внутри определяют другую функцию wrapper, внутри которой мы вызываем функцию
from functools import wraps
class CacheResponse:
def __init__(self, item=5):
self.item = item
def __call__(self, fn):
@wraps(fn)
def wrapper(*args, **kwargs):
print("before function")
print(self.item)
fn(*args, **kwargs)
return wrapper
def cache_response(item):
def actual_dec(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(item)
print(args)
print(kwargs)
print("before function")
func(*args, **kwargs)
print("after function")
return wrapper
return actual_dec
@CacheResponse(item=10)
def welcome():
print("hello")