Для чего нужен декоратор
Понимаем декораторы в Python’e, шаг за шагом. Шаг 1
На Хабре множество раз обсуждалась тема декораторов, однако, на мой взгляд, данная статья (выросшая из одного вопроса на stackoverflow) описывает данную тему наиболее понятно и, что немаловажно, является «пошаговым руководством» по использованию декораторов, позволяющим новичку овладеть этой техникой сразу на достойном уровне.
Итак, что же такое «декоратор»?
Впереди достаточно длинная статья, так что, если кто-то спешит — вот пример того, как работают декораторы:
Те же из вас, кто готов потратить немного времени, приглашаются прочесть длиииинный пост.
Функции в Python’e являются объектами
Для того, чтобы понять, как работают декораторы, в первую очередь следует осознать, что в Python’е функции — это тоже объекты.
Давайте посмотрим, что из этого следует:
Запомним этот факт, скоро мы к нему вернёмся, но кроме того, стоит понимать, что функция в Python’e может быть определена… внутри другой функции!
Ссылки на функции
Ну что, вы всё ещё здесь?:)
Подождите, раз мы можем возвращать функцию, значит, мы можем и передавать её другой функции, как параметр:
Ну что, теперь у нас есть все необходимые знания для того, чтобы понять, как работают декораторы.
Как вы могли догадаться, декораторы — это, по сути, просто своеобразные «обёртки», которые дают нам возможность делать что-либо до и после того, что сделает декорируемая функция, не изменяя её.
Создадим свой декоратор «вручную»
Наверное, теперь мы бы хотели, чтобы каждый раз, во время вызова a_stand_alone_function, вместо неё вызывалась a_stand_alone_function_decorated. Нет ничего проще, просто перезапишем a_stand_alone_function функцией, которую нам вернул my_shiny_new_decorator:
Вы ведь уже догадались, что это ровно тоже самое, что делают @декораторы.:)
Разрушаем ореол таинственности вокруг декораторов
Вот так можно было записать предыдущий пример, используя синтаксис декораторов:
Да, всё действительно так просто! decorator — просто синтаксический сахар для конструкций вида:
Декораторы — это просто pythonic-реализация паттерна проектирования «Декоратор». В Python включены некоторые классические паттерны проектирования, такие как рассматриваемые в этой статье декораторы, или привычные любому пайтонисту итераторы.
Конечно, можно вкладывать декораторы друг в друга, например так:
И используя синтаксис декораторов:
Следует помнить о том, что порядок декорирования ВАЖЕН:
На этом моменте Вы можете счастливо уйти, с осознанием того, что вы поняли, что такое декораторы и с чем их едят.
Для тех же, кто хочет помучать ещё немного свой мозг, завтра будет допереведена вторая часть статьи, посвящённая продвинутому использованию декораторов.
Декораторы в Python: понять и полюбить
Авторизуйтесь
Декораторы в Python: понять и полюбить
Декораторы — один из самых полезных инструментов в Python, однако новичкам они могут показаться непонятными. Возможно, вы уже встречались с ними, например, при работе с Flask, но не хотели особо вникать в суть их работы. Эта статья поможет вам понять, чем являются декораторы и как они работают.
Что такое декоратор?
Новичкам декораторы могут показаться неудобными и непонятными, потому что они выходят за рамки «обычного» процедурного программирования как в Си, где вы объявляете функции, содержащие блоки кода, и вызываете их. То же касается и объектно-ориентированного программирования, где вы определяете классы и создаёте на их основе объекты. Декораторы не принадлежат ни одной из этих парадигм и исходят из области функционального программирования. Однако не будем забегать вперёд, разберёмся со всем по порядку.
Декоратор — это функция, которая позволяет обернуть другую функцию для расширения её функциональности без непосредственного изменения её кода. Вот почему декораторы можно рассматривать как практику метапрограммирования, когда программы могут работать с другими программами как со своими данными. Чтобы понять, как это работает, сначала разберёмся в работе функций в Python.
Как работают функции
Все мы знаем, что такое функции, не так ли? Не будьте столь уверены в этом. У функций Python есть определённые аспекты, с которыми мы нечасто имеем дело, и, как следствие, они забываются. Давайте проясним, что такое функции и как они представлены в Python.
Функции как процедуры
С этим аспектом функций мы знакомы лучше всего. Процедура — это именованная последовательность вычислительных шагов. Любую процедуру можно вызвать в любом месте программы, в том числе внутри другой процедуры или даже самой себя. По этой части больше нечего сказать, поэтому переходим к следующему аспекту функций в Python.
Функции как объекты первого класса
В Python всё является объектом, а не только объекты, которые вы создаёте из классов. В этом смысле он (Python) полностью соответствует идеям объектно-ориентированного программирования. Это значит, что в Python всё это — объекты:
Тот факт, что всё является объектами, открывает перед нами множество возможностей. Мы можем сохранять функции в переменные, передавать их в качестве аргументов и возвращать из других функций. Можно даже определить одну функцию внутри другой. Иными словами, функции — это объекты первого класса. Из определения в Википедии:
Объектами первого класса в контексте конкретного языка программирования называются элементы, с которыми можно делать всё то же, что и с любым другим объектом: передавать как параметр, возвращать из функции и присваивать переменной.
И тут в дело вступает функциональное программирование, а вместе с ним — декораторы.
Функциональное программирование — функции высших порядков
В Python используются некоторые концепции из функциональных языков вроде Haskell и OCaml. Пропустим формальное определение функционального языка и перейдём к двум его характеристикам, свойственным Python:
Функциональному программированию присущи и другие свойства вроде отсутствия побочных эффектов, но мы здесь не за этим. Лучше сконцентрируемся на другом — функциях высших порядков. Что есть функция высшего порядка? Снова обратимся к Википедии:
Функции высших порядков — это такие функции, которые могут принимать в качестве аргументов и возвращать другие функции.
Если вы знакомы с основами высшей математики, то вы уже знаете некоторые математические функции высших порядков порядка вроде дифференциального оператора d/dx. Он принимает на входе функцию и возвращает другую функцию, производную от исходной. Функции высших порядков в программировании работают точно так же — они либо принимают функцию(и) на входе и/или возвращают функцию(и).
Пара примеров
Раз уж мы ознакомились со всеми аспектами функций в Python, давайте продемонстрируем их в коде:
Здесь мы определили простую функцию. Из фрагмента кода далее вы увидите, что эта функция, как и классы с числами, является объектом в Python:
Теперь давайте посмотрим на функции в качестве объектов первого класса.
Мы можем хранить функции в переменных:
Определять функции внутри других функций:
Передавать функции в качестве аргументов и возвращать их из других функций:
Из этих примеров должно стать понятно, насколько функции в Python гибкие. С учётом этого можно переходить к обсуждению декораторов.
Как работают декораторы
Повторим определение декоратора:
Декоратор — это функция, которая позволяет обернуть другую функцию для расширения её функциональности без непосредственного изменения её кода.
Раз мы знаем, как работают функции высших порядков, теперь мы можем понять как работают декораторы. Сначала посмотрим на пример декоратора:
Здесь decorator_function() является функцией-декоратором. Как вы могли заметить, она является функцией высшего порядка, так как принимает функцию в качестве аргумента, а также возвращает функцию. Внутри decorator_function() мы определили другую функцию, обёртку, так сказать, которая обёртывает функцию-аргумент и затем изменяет её поведение. Декоратор возвращает эту обёртку. Теперь посмотрим на декоратор в действии:
Иными словами, выражение @decorator_function вызывает decorator_function() с hello_world в качестве аргумента и присваивает имени hello_world возвращаемую функцию.
И хотя этот декоратор мог вызвать вау-эффект, он не очень полезный. Давайте взглянем на другие, более полезные (наверное):
Здесь мы создаём декоратор, замеряющий время выполнения функции. Далее мы используем его на функции, которая делает GET-запрос к главной странице Google. Чтобы измерить скорость, мы сначала сохраняем время перед выполнением обёрнутой функции, выполняем её, снова сохраняем текущее время и вычитаем из него начальное.
После выполнения кода получаем примерно такой результат:
К этому моменту вы, наверное, начали осознавать, насколько полезными могут быть декораторы. Они расширяют возможности функции без редактирования её кода и являются гибким инструментом для изменения чего угодно.
Используем аргументы и возвращаем значения
В приведённых выше примерах декораторы ничего не принимали и не возвращали. Модифицируем наш декоратор для измерения времени выполнения:
Вывод после выполнения:
Как вы видите, аргументы декорируемой функции передаются функции-обёртке, после чего с ними можно делать что угодно. Можно изменять аргументы и затем передавать их декорируемой функции, а можно оставить их как есть или вовсе забыть про них и передать что-нибудь совсем другое. То же касается возвращаемого из декорируемой функции значения, с ним тоже можно делать что угодно.
Декораторы с аргументами
Мы также можем создавать декораторы, которые принимают аргументы. Посмотрим на пример:
Здесь мы модифицировали наш старый декоратор таким образом, чтобы он выполнял декорируемую функцию iters раз, а затем выводил среднее время выполнения. Однако чтобы добиться этого, пришлось воспользоваться природой функций в Python.
Да, это может быть действительно сложно уместить в голове, поэтому держите правило:
Декоратор принимает функцию в качестве аргумента и возвращает функцию.
Объекты-декораторы
Напоследок стоит упомянуть, что не только функции, а любые вызываемые объекты могут быть декоратором. Экземпляры классов/объекты с методом __call__() тоже можно вызывать, поэтому их можно использовать в качестве декораторов. Эту функциональность можно использовать для создания декораторов, хранящих какое-то состояние. Например, вот декоратор для мемоизации:
Тут будут перечислены некоторые важные вещи, которые не были затронуты в статье или были затронуты вскользь. Вам может показаться, что они расходятся с тем, что было написано в статье до этого, но на самом деле это не так.
Заключение
Надеемся, эта статья помогла вам понять, какая «магия» лежит в основе работы декораторов.
Декораторы Python: хватит это терпеть
Всем привет! В этой статье я расскажу об инструменте, разработанном мной, который изменяет работу декораторов в Python и делает их более «Питоничными».
Я не буду рассказывать про области применения декораторов. Есть множество статей на эту тему.
Для начала, давайте вспомним: что же такое декораторы в Пайтон.
Если совсем просто, то это удобный способ передать одну функцию в другую и получить третью. В этом определении нет ни одного слова правды, но мы вернёмся к этому позже.
Как работают декораторы
Так выглядит функция-декоратор. Как вы можете увидеть, она принимает в качестве аргумента другую функцию. Затем с этой функцией что-то делают внутри вложенной функции-обёртки и возвращают из декоратора уже обёртку вместо исходной функции.
Теперь можно декорировать:
Важно помнить!
Декоратор исполняется только один раз: при объявлении оборачиваемой функции. При дальнейшем вызове функции исполняется только вложенная функция wrapper .
Мы это увидим, если добавим две строчки в наш декоратор:
А вот и страдания: аргументы функции и аргументы декоратора
У функции, которую мы декорируем, могут быть аргументы. Принимает их вложенная функция wrapper :
А ещё, аргументы могут быть переданы непосредственно в декоратор:
Как Вам код? Вспомним, мантру Питонистов из начала статьи:
Ничего, на помощь придёт DecoratorHelper! Но, перед этим, ещё пара слов о декораторах.
Мифы декораторов
Декораторы удобны. Думаю, с этим мы уже разобрались.
Декоратор возвращает функцию. Декоратор может возвращать что угодно. Стоит лишь помнить, что если декоратор возвращает не callable объект, то вызывать его не получится.
DecoratorHelper: решение проблем
Импортируем и используем как декоратор:
Что это даёт?
Вы больше не думаете над тем, будут ли аргументы у декоратора. DecoratorHelper думает об этом вместо Вас.
Вы получаете удобный, Питоничный доступ ко всем аргументам, самой функции, к тому, что будет происходить до и после выполнения функции.
В итоге Вы получаете вместо функции объект, который имеет следующие атрибуты:
Как использовать?
Перепишем приведённый ранее код декоратора, который может принимать/не принимать аргументы:
Как мы можем видеть, тело декоратора сократилось в 8 раз. Profit!
Ограничение! Первым аргументом нельзя передавать callable объекты, иначе всё сломается 🙂 Думаю, для большинства задач, это не смертельно.
Что дальше?
В следующих версиях планируется:
Улучшенная обработка аргументов.
Встроенный счётчик вызовов.
Возможность превратить объект в синглтон.
Возможность превратить объект в буилдер.
Может быть, возможность подключить асинхронность.
И всё это в максимально удобном формате: singleton = True.
P. S. Если в комментариях будет интерес к теме, напишу вторую статью о том, как DecoratorHelper устроен. Но сразу скажу, что это уровень Junior+.
Декоратор
Декоратор (от англ. «decorate» — «украшать») — специалист по художественному оформлению и украшению интерьеров помещений: частных домов, театральных спектаклей, съемок, банкетных залов в ресторанах, офисов, бизнес-центров с использованием архитектурных, графических средств, живописи, освещения и постановочной техники. Кстати, в 2021 году центр профориентации ПрофГид разработал точный тест на профориентацию. Он сам расскажет вам, какие профессии вам подходят, даст заключение о вашем типе личности и интеллекте.
Профессию декоратора часто сравнивают с деятельностью дизайнера. Но такое сравнение некорректно: декоратор создает уникальный интерьер под определенный заказ, в котором, тем не менее, проявляется и его творческая индивидуальность, а дизайнер подает идеи для массового производства. Декоратор не углубляется в технические аспекты перепланировки помещений, не изменяет геометрию пространства, а создает образ, наполняя его своей идеей и уникальным содержанием, воплощенными в материалах, предметах, вещах. Не проводя кардинальных изменений, декоратор может создать совершенно новую атмосферу пространства. Умелое декорирование может исправить любые недостатки и проблемы. Декоратор может эффективно использовать тесное пространство, изобретательно оформить окно, подобрать оригинальное цветовое сочетание, функционально и красиво расставить мебель в квартире, преобразовать интерьер с помощью текстиля, статуэток, вазочек, декоративных свечей. Особый уют, теплоту и красоту предметам интерьера придают светильники. Они творят настоящее чудо, создавая интригу, выделяя и подчеркивая тенями декоративную штукатурку и лепнину.
Как правило, идеи декоратора должны быть созвучны и гармоничны с внутренним миром заказчика, но при этом в них ярко проявляется индивидуальность самого декоратора. Свежая неординарная идея профессионала может неузнаваемо изменить стиль дома, сформировать новый имидж и повлиять на жизненный статус.
Интерьеры декораторов — это, прежде всего, коктейли идей, которые делают любое помещение уникальным по форме, фактуре, цвету и свету. Декоратор выступает не только как художник, но и как психоаналитик. Он знает психологическое и физиологическое воздействие цветов на человека. Например, некоторые оттенки синего цвета угнетающе действуют на людей в жилом интерьере, а преобладание красного цвета повышает артериальное давление. В современном мире профессия декоратора востребована как никогда. Декоратор может превратить обыденный интерьер в произведение искусства, в котором каждый может почувствовать себя героем прекрасной истории. Кроме того, декоратор помогает заказчику эффективно распределить бюджет.
Профессия декоратора — творческая и увлекательная. Его можно назвать творцом настроения, создающим фон красивой жизни!
Особенности профессии
В целом, функциональные обязанности декоратора заключаются в следующем:
Плюсы и минусы профессии
Плюсы: творческая интересная работа, модная, востребованная и уникальная профессия. В настоящее время многие люди мечтают оформить свои дома в индивидуальном авторском стиле.
Минусы: ответственность, возможность несовпадения вкуса заказчика с выполненной работой.
Место работы
Мастерские дизайна и декора, театры, шоу-программы, бюро Artistic Design, некоммерческое партнерство ОДИ «Объединение декораторов интерьеров», частная практика.
Готовимся к собеседованию: что такое декораторы в Python
На собеседованиях только и разговоров, что о декораторах. Разбираемся на пальцах, что это.
Итак, вы на собеседовании на вакансию джуна-пайтониста. Всё идёт хорошо: вы объяснили про кортежи и списки, про принципы ООП и структуры данных, даже решили небольшую задачку, и вдруг:
— Расскажите, пожалуйста, про декораторы в Python.
Простой ответ
В большинстве случаев будет достаточно сказать своими словами, что такое декоратор, и написать простейший код.
— Декоратор, если в двух словах, это функция, которая добавляет новую функциональность к другой функции без изменения её кода. Он как бы оборачивает, декорирует функцию, тем самым расширяя её возможности.
Функция say_hi (пример отсюда), которую мы «обернём» в декоратор, возвращает строку «всем привет». Обратите внимание: не печатает, а возвращает.
С некоторых пор утверждает, что он data scientist. В предыдущих сезонах выдавал себя за математика, звукорежиссёра, радиоведущего, переводчика, писателя. Кандидат наук, но не точных. Бесстрашно пишет о Data Science и программировании на Python.
А наш декоратор превратит символы этой строки из строчных в прописные. Этой возможности у функции say_hi раньше не было, а теперь будет.
Что здесь происходит — разбираем код построчно:
Больше локальных переменных богу локальных переменных! Конечно, всё это ради понятности и читаемости.
Как это запустить? Пишем символ @, за ним название декоратора, а объявление функции say_hi переносим на строку под ней: