Декораторы предназначены для модификации функций с помощью других функций.
Они вам очень пригодятся, когда вам нужно изменить поведение функции, но вы не хотите ее модифицировать.

def decor(func):
  def wrap():
    print("============")
    func()
    print("============")
  return wrap

def print_text():
  print("Hello world!")

decorated = decor(print_text)
decorated()


Мы определили функцию с именем decor, у которой один единственный параметр func. Внутри функции decor, мы определили вложенную функцию с именем wrap. Функция wrap выведет строку, затем вызовет func() и выведет еще одну строку. Функция decor возвращает функцию wrap как свой результат.
Можно сказать, что переменная decorated – декорированная версия print_text, то есть print_text плюс что-то еще.
Предположим, мы написали полезный декоратор и хотели бы полностью заменить print_text декорированной версией, так чтобы всегда выполнялась наша версия print_text «плюс что-то еще».
Это делается путем повторного присвоения переменной, содержащей нашу функцию:

print_text = decor(print_text)
print_text()


В предыдущем примере, мы декорировали нашу функцию, заменив переменную, содержащую функцию, на ее «обернутую» версию.

def print_text():
    print("Hello world!")

print_text = decor(print_text)



Эта конструкция может быть использована в любой момент для оборачивания любой нужной функции.
Python предоставляет способ обернуть функцию в декоратор; для этого нужно поставить перед определением функции имя декоратора и символ @.
Если определяется функция, мы можем «декорировать» ее, добавив символ @; вот как:

@decor
def print_text():
    print("Hello world!")

Результат будет тот же, что и в примере выше.