Прежде, чем говорить о декораторах, нужно кое-что узнать о функциях в Python. Допустим, у нас есть функция, которая здоровается с Юпи:
def hey_Jupi():
print("Привет, Юпи!")
Функции в Python — это объекты первого класса, ничем не хуже, чем int’ы или словари. Это значит, что:
Функцию можно присвоить переменной:
say_hi = hey_Jupi
say_hi()
# Привет, Юпи!
Функцию можно вернуть из функции:
def wrapper(func):
print("Юпи пришла.")
return func
hello_Jupi = wrapper(hey_Jupi)
# Юпи пришла.
hello_Jupi()
# Привет, Юпи!
Функцию можно определить внутри другой функции:
def deco(func):
def wrapper():
print("Юпи пришла.")
func()
return wrapper
hey_Jupi = deco(hey_Jupi)
hey_Jupi()
# Юпи пришла.
# Привет, Юпи!
Смотрите, что получилось на последнем шаге. На этапе создания deco никакой код не выполняется — мы заходим в deco, видим, что здесь определена функция wrapper и возвращаем ее. Таким образом мы подменяем исходную hey_Jupi на wrapper и получаем новое поведение hey_Jupi, не изменяя ее код!
Это и называется декоратор. Это настолько удобный и мощный инструмент, что в Python для него придумали специальный синтаксический сахар. При условии, что функция deco у нас уже определена так же, как выше, можно добавить название декоратора с символом @ перед определением функции и получить эквивалентное поведение:
@deco
def hey_Jupi():
print("Привет, Юпи!")
hey_Jupi()
# Юпи пришла.
# Привет, Юпи!
Кстати, этот же декоратор можно применить и к любой другой функции:
@deco
def take_five():
print("Юпи, дай пять!")
take_five()
# Юпи пришла.
# Юпи, дай пять!
Декораторы круты тем, что позволяют гибко модифицировать поведение функции, применять одну и ту же модификацию к нескольким функциям сразу и даже менять поведение функций, доступа к коду которых у нас нет! Зачем нам декораторы на реальных проектах?
- Декораторы используют в веб фреймворках для проверки авторизации или для разделения групп пользователей. Например, часть методов доступна только авторизованным пользователям, либо пользователям с определенной ролью, а остальные методы — всем. Для этого нужные методы оборачивают в декораторы, которые делают необходимые проверки.
- Декораторы позволяют проверить, что аргументы функции имеют нужный тип и значения. Это можно сделать на входе в функцию, но иногда проверки переносят в функцию-обертку.
- С помощью декоратора можно замерять время выполнения функций.