Асинхронное программирование потоково обрабатывает пользовательское пространство. Здесь уже не процессор участвует в переключении контекста, а само приложение, и происходит это в заранее заданных точках. Теперь, вы можете просто уйти счастливыми или еще немного поднапрячь мозги и узнать как использовать декораторы на более продвинутом уровне. То есть если предыдущий процесс все еще находится на этапе выполнения, асинхронная программа может легко перейти к обработке следующих задач.
3_Вимоги_1 / 09.03.12 / Python / Учебник / Основы Python_7
В самом начале хочется отметить, что рассматриваемый здесь декоратор (decorator) как элемент языка Python не является реализацией одноимённого паттерна проектирования, его возможности гораздо шире, хотя сам паттерн и может быть реализован через питоновский декоратор.
Что такое декоратор и простейшие способы его использования
Итак, декоратор — это удобный способ изменения поведения некоторой функции (а начиная с Python 2.6 и 3.0 и целого класса). С точки зрения синтаксиса выглядит достаточно просто. Например, следующий фрагмент кода, использующий декоратор:
Слово «эквивалентен» нужно понимать буквально: операция выполняется в момент определения функции один раз и если f1 вернёт, скажем, None, то в переменной func будет записан None. Простой пример (декорирующая функция возвращает None, в итоге func тоже оказывается равным None):
Давайте рассмотрим более практичный пример. Допустим, нужно проверить, как быстро работает некоторая функция, нужно знать, сколько времени отнимает каждый её вызов. Задача элементарно решается при помощи декоратора.
func(1, 2) # напечатает что-то типа: Время выполнения функции: 0.0004
И определим функцию func следующим образом (используя сразу два декоратора — pause и timer):
Теперь вызов func(1, 2) покажет общее время исполнения примерно одну секунду.
Более сложное использование декораторов
Вам могло показаться, что в качестве декоратора можно использовать только функцию. Это не так. В качестве декоратора может выступать любой объект, который можно «вызвать». Например, в качестве декоратора может выступать класс. Вот значительно более сложный пример, показывающий, как можно конструировать потоки (threads) при помощи декораторов:
В нашем же случае декорируемая функция передаётся в качестве аргумента конструктору класса потока, где присваивается компоненту класса run. Для создания нескольких разных потоков вам нужно дважды продублировать «классический» код. А при использовании «потоковых» декораторов — только добавить вызов декоратора к функции потока.
Пример с потоком приведён исключительно в ознакомительных целях. В реальности его нужно использовать очень аккуратно, поскольку не весь потоковый код можно обернуть в описанный здесь декоратор.
В декоратор можно передавать параметры, запись вида:
По сути это означае, что декоратором является результат выполнения функции f1(123). Давайте напишем обновлённый декоратор pause(), который позволяет указывать величину паузы перед выполненением оборачиваемой функции:
Обратите внимание, как декоратор фактически создаётся динамически внутри функции pause().
Использование декораторов в классах
Использование декораторов на методах классов ничем не отличается от использования декораторов на обычных функциях. Однако для классов есть предопределённые декораторы статических методов и методов класса соответственно. Вот пример их использования:


Декораторы Python от начала до конца
Что бы понять что такое декораторы, для начала вы должны понять, что функции в python — это объекты. Данное понимание очень важно. Давайте разберем это на простом примере: Для получения более широкого представления, давайте ознакомимся еще с одним примером того, как декоратор будет использоваться. Статические значения переменных создаются вместе с функцией через оператор присваивания так, как если бы инициализация происходила в теле.
Декораторы
Фактически, любой объект, который имеет специальный метод __cal__() является вызываемым. В общем смысле – декораторы являются вызываемыми объектами, которые возвращают другой вызываемый объект. Как правило – декоратор принимает функцию, добавляет некоторую функциональность к ней, и возвращает её:
В этом примере make_pretty() является декотратором. Во время присвоения:
Функция ordinary() становится “декорированной”, а функции, которая возвращается из make_pretty() присваивается имя pretty . Мы видим, что декоратор добавил новую функциональность к оригинальной функции ordinary() . Этот процесс схож с упаковкой подарка – декторатор выполняет роль обёртки. Суть поведения объекта, которые подвергся “декорации” (как подарок внутри упаковки) – не меняется.
Обычно мы “декорируем” функцию и присваиваем ей какое-то имя, как в примере выше:
Это распростраённое действие, поэтому у Python имеется специальный синтаксис для таких случаев – мы можем использовать символ @ с именем функции-декоторатора, и разместить её перед функцией, которая будет передана декоратору, например – такой код:


Декораторы в Python
Теперь асинхронные приложения Python используют сопрограммы в качестве основного ингредиента. Для их запуска они используют библиотеку Asyncio. Но есть и другие важные элементы, которые также можно считать ключевыми для асинхронных приложений: То есть если предыдущий процесс все еще находится на этапе выполнения, асинхронная программа может легко перейти к обработке следующих задач. Функции, которые принимают другие функции в качестве аргументов называются функциями высшего порядка higher order functions.
Передаем аргументы в декоратор
Великолепно! Но что вы скажете насчет того, что бы передать аргументы в сам декоратор? Ну конечно нам придется немного извернуться, потому что декоратор должен принимать функцию, как аргумент и по этой причине, вы не сможете передать аргументы декорируемой функции напрямую в декоратор.
Перед тем как устремиться к решению задачи, давайте напишем небольшую напоминалку:
На деле — это тоже самое. Просто вызывается «my_decorator». Так что когда вы пишите @my_decorator, вы просто говорите Python вызвать функцию определенную переменной «my_decorator». Это очень важно, потому что метка [наименование переменной] может непосредственно указывать на декоратор… или нет! Давайте погрузимся во зло!
Здесь никаких сюрпризов. Давайте сделаем ТОЧНО такую же штуку, но пропустим промежуточные переменные:
Эй, вы это видели? Мы использовали вызов функции с «@» синтаксисом 🙂
Вернемся обратно к декораторам с аргументами. Если мы можем использовать функцию, чтобы генерировать декоратор на лету, мы можем передать аргументы в эту функцию, верно?
Вот он, декоратор с аргументами. Аргументы могут быть назначены переменными:


Рекомендуемая литература
Содержание:







