Декораторы в Python
Оберните функцию дополнительным поведением, не трогая её код
@decorator — просто удобное сокращение для переприсваивания функции её обёрнутой версии. Так можно добавить логирование, замер времени, кэширование или проверку доступа сразу многим функциям, не редактируя ни одну из них.
- объяснить, почему функции — это объекты первого класса,
- написать вложенную функцию-обёртку, которая замыкается над другой функцией,
- создать декоратор и применить его через
@, - передавать любые аргументы через
*args, **kwargs, - сохранять исходное имя и строку документации с помощью
functools.wraps.
1. Функции — объекты первого класса
Прежде чем декораторы обретут смысл, запомните один факт: в Python функция — это обычный объект, как число или список. Её можно сохранить в переменной, положить в список, передать в другую функцию как аргумент и даже вернуть из функции.
def shout(text):
return text.upper()
yell = shout # store the function object (no parentheses!)
print(yell("hello")) # HELLO
def run_twice(func, value):
return func(value) + " " + func(value)
print(run_twice(shout, "hi")) # HI HI
Обратите внимание: в yell = shout нет скобок — мы копируем саму функцию, а не её результат. Именно на этой возможности передавать функции и строится декоратор.
2. Вложенные функции и замыкания
Функцию можно определить внутри другой функции. Внутренняя функция может читать переменные внешней и сохраняет ссылку на них даже после того, как внешняя функция завершилась. Внутреннюю функцию, которая помнит значения из объемлющей области видимости, называют замыканием.
def make_multiplier(factor):
def multiply(n):
return n * factor # 'factor' comes from the outer scope
return multiply # return the inner function object
triple = make_multiplier(3)
print(triple(10)) # 30
print(triple(4)) # 12
make_multiplier возвращает внутреннюю функцию multiply, которая по-прежнему помнит factor = 3. Декоратор устроен точно так же: внешняя функция определяет и возвращает внутреннюю обёртку.