Привет. В этом видео мы с вами поговорим о декораторах,
и это очень важная концепция, которую действительно нужно понять,
потому что они используются повсеместно практически
во всех приложениях на Python'е.
Итак,
декоратор — это функция, которая принимает функцию
и возвращает функцию.
Это очень важный момент, пожалуйста, запомните это.
Просто
функция, принимающая одну функцию,
возвращающая другую функцию.
Как вы уже знаете,
в Python'е функция — это объект первого класса,
поэтому их можно возвращать, принимать
и производить с ними разные операции.
Итак, простейший декоратор просто возвращает функцию
и возвращает её же,
то есть такой identity декоратор, который ничего не делает.
Однако, часто бывает полезно
с функцией что-то делать, и мы с вами это сейчас как раз обсудим.
Синтаксис применения декоратора в Python'е такой.
На самом деле, это просто так называемый синтаксический сахар,
и происходит здесь именно это.
У нас вызывается декоратор,
ему передаётся функция и записывается всё
в функцию, которую мы декорируем.
Делается это обычно как раз с помощью @.
Не нужно этого бояться, происходит здесь
довольно простой момент вот такой.
Итак,
однако, как вы понимаете, довольно скучно просто возвращать
саму же функцию, и нет в этом никакого смысла.
Часто бывает необходимо вернуть не ту же самую функцию,
а какую-то модифицированную функцию
или вообще новую функцию совершенно другую.
Например, ещё один простой декоратор, мы можем
его определить, он принимает функцию,
определяет внутри какую-то новую функцию
и возвращает её.
Таким образом, у нас при применении декоратора, если мы вызовем
decorated,
не вызовется hello, потому что вернётся, на самом деле,
функция new_func,
и мы будем вызывать уже функцию new_func.
Можем это проверить,
если посмотрим на её имя.
На самом деле, decorated — это new_func,
потому что
опять же у нас вот такой вот синтаксис.
У нас декоратор вернул другую функцию,
и в decorated записалась новая функция new_func.
Важно это понимать.
Итак,
давайте попробуем сразу перейти к практике, чтобы
поподробнее разобраться с тем, как это работает.
И напишем декоратор, который записывает в лог
результаты выполнения функции.
Вообще для чего обычно используются декораторы?
Чаще всего они используются для того, чтобы модифицировать
поведение каких-то функций.
Часто бывает необходимо
использовать один декоратор, для того чтобы
какое-то семейство функций переопределить,
модифицировать их поведение.
Например, у нас может быть декоратор login_required,
который мы можем применять к разным функциям
и требовать, чтобы в момент исполнения этой функции человек был
залогинен на сайте.
Или мы можем опять же логировать какую-то информацию,
можем считать какие-то метрики,
и написав один декоратор, мы можем модифицировать поведение
сразу многих функций.
Это очень полезный и мощный концепт,
который, собственно, мы с вами сейчас рассмотрим.
Итак, у нас декоратор, который просто пишет что-то,
что произошло в функции, в файл.
Мы вот здесь вот определили наш декоратор, назовём его logger,
и вот так вот он будет применяться.
И теперь при вызове summator'а мы хотим, чтобы у нас
результат выполнения summator'а записывался в лог-файл.
Также мы можем этот декоратор применять к любой другой функции.
У нас всегда результат выполнения будет записываться в файл
вне зависимости от того, какая это функция.
Давайте попробуем это сделать.
Итак, мы определили наш декоратор,
и нам нужно из него очевидно вернуть какую-то новую функцию.
Давайте назовём ее wrapped.
Обычно функции, которые определены внутри декоратора,
называются wrapped, decorated, inner, что-то в этом роде,
чтобы понять, что это действительно то новое,
чем мы переопределяем изначальную функцию.
И у нас функция будут принимать num_list для начала,
также как и наш summator, потому что мы заменим наш summator
на этот wrapped(num_list).
Мы потом вернём его, перезаписав summator.
Что же здесь должно происходить?
Воспользуемся знакомым вашим концептом замыкания
и вызовем нашу функцию,
передав ей num_list,
и, например,
откроем файл
и запишем в него результат выполнения.
Не забудем вернуть result, потому что мы хотим, чтобы у нас,
на самом деле, всё работало.
Итак, мы написали наш декоратор.
Что здесь происходит?
Мы, применяя декоратор, подменяем функцию summator
новой функцией wrapped, и именно она уже будет выполняться.
Эта функция новая, она принимает num_list, так же как и summator,
получает результат работы summator'а, записывает
результат в файл и просто возвращается.
Давайте попробуем вызвать summator.
У нас вернулось 15, потому что сумма, действительно, 15.
Давайте попробуем открыть файл log.txt
и убедиться, что там действительно что-то записано.