Декоратор что такое: Декораторы в Python: понять и полюбить

Что такое декоратор? — Intermediate Python

Декораторы — важная часть Python. Если коротко: они являются функциями, которые изменяют работу других функций. Они помогают делать код короче и более «питонистичным». Большинство новичков не знает, где их использовать, так что я расскажу о нескольких случаях, когда декораторы помогут написать лаконичный код.

Для начала рассмотрим, как написать свой собственный декоратор.

Это будет самым сложным моментом в теме, поэтому мы будем продвигаться шаг за шагом, так что вы сможете все полностью понять.

Все в Python является объектом

Для начала краткая ретроспектива функций в Python:

def hi(name=»yasoob»):

return «Привет » + name

print(hi())

# Вывод: ‘Привет yasoob’

# Мы можем присвоить функцию переменной:

greet = hi

# Мы не используем здесь скобки, поскольку наша задача не вызвать функцию,

# а передать её объект переменной. Теперь попробуем запустить

print(greet())

# Вывод: ‘Привет yasoob’

# Посмотрим, что произойдет, если мы удалим ссылку на оригинальную функцию

del hi

print(hi())

# Вывод: NameError

print(greet())

# Вывод: ‘Привет yasoob’

Определение функций внутри функций

Итак, это были основы работы с функциями. Теперь продвинемся на шаг дальше. В Python разрешено объявлять функции внутри других функций:

def hi(name=»yasoob»):

print(«Вы внутри функции hi()»)

def greet():

return «Вы внутри функции greet()»

def welcome():

return «Вы внутри функции welcome()»

print(greet())

print(welcome())

print(«Вы внутри функции hi()»)

# Вывод: Вы внутри функции hi()

# Вы внутри функции greet()

# Вы внутри функции welcome()

# Вы внутри функции hi()

# Пример демонстрирует, что при вызове hi() вызываются также функции

# greet() и welcome(). Кроме того, две последние функции недоступны

# извне hi():

greet()

# Вывод: NameError: name ‘greet’ is not defined

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

Возвращение функции из функции

Нам не обязательно исполнять функцию, определенную внутри другой функции сразу, мы можем вернуть её в качестве возвращаемого значения:

def hi(name=»yasoob»):

def greet():

return «Вы внутри функции greet()»

def welcome():

return «Вы внутри функции welcome()»

if name == «yasoob»:

return greet

return welcome

a = hi()

print(a)

# Вывод: <function greet at 0x7f2143c01500>

# Это наглядно демонстрирует, что переменная `a` теперь указывает на

# функцию greet() в функции hi(). Теперь попробуйте вот это

print(a())

# Вывод: Вы внутри функции greet()

Давайте еще раз пробежимся по коду. Через условный оператор мы возвращаем из функции объекты greet и welcome, а не greet() и welcome(). Почему? Потому что скобки означают вызов функции, без них мы просто передаем сам объект функции. Достаточно ясно? Давайте я чуть подробнее остановлюсь на этом. Когда мы пишем a = hi(), функция hi() исполняется и (поскольку имя по умолчанию yasoob) возвращается функция greet. Если мы изменим код на a = hi(name="ali"), то будет возвращена функция welcome. Мы также можем набрать hi()(), что вернет Вы внутри функции greet().

Передаем функцию в качестве аргумента другой функции

def hi():

return «Привет yasoob!»

def doSomethingBeforeHi(func):

print(«Я делаю что-то скучное перед исполнением hi()»)

print(func())

doSomethingBeforeHi(hi)

# Вывод: Я делаю что-то скучное перед исполнением hi()

# Привет yasoob!

Теперь у нас есть все необходимые знания для изучения работы декораторов. Декораторы позволяют нам исполнять определенный код до и после исполнения конкретной функции.

Пишем наш первый декоратор

В прошлом примере мы по сути уже написали декоратор! Давайте изменим его и сделаем немного более полезным:

def a_new_decorator(a_func):

def wrapTheFunction():

print(«Я делаю что-то скучное перед исполнением a_func()»)

a_func()

print(«Я делаю что-то скучное после исполнения a_func()»)

return wrapTheFunction

def a_function_requiring_decoration():

print(«Я функция, которая требует декорации»)

a_function_requiring_decoration()

# Вывод: «Я функция, которая требует декорации»

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

# Теперь функция a_function_requiring_decoration обернута в wrapTheFunction()

a_function_requiring_decoration()

# Вывод: Я делаю что-то скучное перед исполнением a_func()

# Я функция, которая требует декорации

# Я делаю что-то скучное после исполнения a_func()

Все ясно? Мы просто использовали принципы, с которыми познакомились выше. Это то, чем и занимаются декораторы в Python! Они «обертывают» функцию и модифицируют её поведение определенным образом. Сейчас вы можете спросить, почему мы не используем в коде символ @. Это просто более короткий способ декорировать функции. Вот как мы можем модифицировать пример выше с использованием @:

@a_new_decorator

def a_function_requiring_decoration():

«»»Эй ты! Задекорируй меня полностью!»»»

print(«Я функция, которая требует декорации»)

a_function_requiring_decoration()

# Вывод: Я делаю что-то скучное перед исполнением a_func()

# Я функция, которая требует декорации

# Я делаю что-то скучное после исполнения a_func()

# Выражение @a_new_decorator это сокращенная версия следующего кода:

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

Надеюсь, теперь у вас есть базовое представление о логике работы декораторов в Python. Однако, у нашего кода есть одна проблема. Если мы исполним:

print(a_function_requiring_decoration. __name__)

# Вывод: wrapTheFunction

Мы этого не ожидали! Имя функции должно быть a_function_requiring_decoration. В реальности наша функция была заменена на wrapTheFunction. Она перезаписала имя и строку документации оригинальной функции. К счастью, Python предоставляет нам простой инструмент для обхода этой проблемы — functools.wraps. Давайте исправим предыдущий пример, используя functools.wraps:

from functools import wraps

def a_new_decorator(a_func):

@wraps(a_func)

def wrapTheFunction():

print(«Я делаю что-то скучное перед исполнением a_func()»)

a_func()

print(«Я делаю что-то скучное после исполнения a_func()»)

return wrapTheFunction

@a_new_decorator

def a_function_requiring_decoration():

«»»Эй ты! Задекорируй меня полностью!»»»

print(«Я функция, которая требует декорации»)

print(a_function_requiring_decoration. __name__)

# Вывод: a_function_requiring_decoration

Так намного лучше. Давайте двигаться дальше и знакомиться с конкретными вариантами использования декораторов.

Макет:

from functools import wraps

def decorator_name(f):

@wraps(f)

def decorated(*args, **kwargs):

if not can_run:

return «Функция не будет исполнена»

return f(*args, **kwargs)

return decorated

@decorator_name

def func():

return(«Функция исполняется»)

can_run = True

print(func())

# Вывод: Функция исполняется

can_run = False

print(func())

# Вывод: Функция не будет исполнена

Примечание: @wraps принимает на вход функцию для декорирования и добавляет функциональность копирования имени, строки документации, списка аргументов и т. д. Это открывает доступ к свойствам декорируемой функции из декоратора.

Варианты использования

Теперь давайте рассмотрим области, где декораторы действительно показывают себя и существенно упрощают работу.

Авторизация

Декораторы могут использоваться в веб-приложениях для проверки авторизации пользователя перед тем, как открывать ему доступ к функционалу. Они активно используются в веб-фреймворках Flask и Django. Вот пример проверки авторизации на декораторах:

Пример:

from functools import wraps

def requires_auth(f):

@wraps(f)

def decorated(*args, **kwargs):

auth = request.authorization

if not auth or not check_auth(auth.username, auth.password):

authenticate()

return f(*args, **kwargs)

return decorated

Журналирование

Журналирование — другая область, в которой декораторы находя широкое применение. Вот пример:

from functools import wraps

def logit(func):

@wraps(func)

def with_logging(*args, **kwargs):

print(func.__name__ + » была исполнена»)

return func(*args, **kwargs)

return with_logging

@logit

def addition_func(x):

«»»Считаем что-нибудь»»»

return x + x

result = addition_func(4)

# Вывод: addition_func была исполнена

Уверен, вы уже думаете о каком-нибудь хитром использовании декораторов.

Декораторы с аргументами

Тогда подумайте вот о чем, является ли @wraps также декоратором? Но, @wraps же принимает аргумент, как нормальная функция. Тогда почему бы нам не сделать что-то похожее с нашими декораторами?

Когда мы используем синтаксис @my_decorator мы применяем декорирующую функцию с декорируемой функцией в качестве параметра. Как вы помните, все в Python является объектом, в том числе и функции! Помня это, мы можем писать функции, возвращающие декорирующие функции.

Вложенные декораторы внутри функции

Давайте вернемся к нашему примеру с журналированием и напишем декоратор, который позволит нам задавать файл для сохранения логов:

from functools import wraps

def logit(logfile=’out.log’):

def logging_decorator(func):

@wraps(func)

def wrapped_function(*args, **kwargs):

log_string = func.__name__ + » была исполнена»

print(log_string)

# Открываем логфайл и записваем данные

with open(logfile, ‘a’) as opened_file:

# Мы записываем логи в конкретный файл

opened_file.write(log_string + ‘\n’)

return wrapped_function

return logging_decorator

@logit()

def myfunc1():

myfunc1()

# Вывод: myfunc1 была исполнена

# Файл out.log создан и содержит строку выше

@logit(logfile=’func2. log’)

def myfunc2():

myfunc2()

# Вывод: myfunc2 была исполнена

# Файл func2.log создан и содержит строку выше

Декораторы из классов

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

К счастью, классы также можно использовать для создания декораторов. Давайте опробуем эту методику:

class logit(object):

def __init__(self, logfile=’out.log’):

self.logfile = logfile

def __call__(self, func):

log_string = func.__name__ + » была исполнена»

print(log_string)

# Открываем логфайл и записваем данные

with open(self. logfile, ‘a’) as opened_file:

# Мы записываем логи в конкретный файл

opened_file.write(log_string + ‘\n’)

# Отправляем сообщение

self.notify()

def notify(self):

# Только записываем логи

Такое решение имеет дополнительно преимущество в краткости, в сравнении с вложенными функциями, при этом синтаксис декорирования функции остается прежним:

@logit()

def myfunc1():

Теперь давайте возьмем подкласс logit и добавим функционал отправки email (эта тема не будет здесь рассмотрена):

class email_logit(logit):

Реализация logit для отправки писем администраторам при вызове

функции

def __init__(self, email='[email protected]’, *args, **kwargs):

self.email = email

super(email_logit, self).__init__(*args, **kwargs)

def notify(self):

# Отправляем письмо в self.email

# Реализация не будет здесь приведена

@email_logit будет работать также как и @logit, при этом отправляя сообщения на почту администратору помимо журналирования.

Декораторы в Python / Skillbox Media

#статьи

  • 11

На собеседованиях только и разговоров, что о декораторах. Разбираемся на пальцах, что это.

Vkontakte Twitter Telegram Скопировать ссылку

 vlada_maestro / shutterstock

Цокто Жигмытов

Кандидат философских наук, специалист по математическому моделированию. Пишет про Data Science, AI и программирование на Python.

Итак, вы на собеседовании на вакансию джуна-пайтониста. Всё идёт хорошо: вы объяснили про кортежи и списки, про принципы ООП и структуры данных, даже решили небольшую задачку, и вдруг:

— Расскажите, пожалуйста, про декораторы в Python.

В большинстве случаев будет достаточно сказать своими словами, что такое декоратор, и написать простейший код.

Вслух:

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

Пример кода:

Функция say_hi (пример отсюда), которую мы «обернём» в декоратор, возвращает строку «всем привет». Обратите внимание: не печатает, а возвращает.

def say_hi():
    return 'всем привет'

А наш декоратор превратит символы этой строки из строчных в прописные. Этой возможности у функции say_hi

раньше не было, а теперь будет.

Пишем декоратор:

def uppercase_decorator(function):
    def wrapper():
        func = function()
        make_uppercase = func.upper()
        return make_uppercase
    return wrapper

Что здесь происходит — разбираем код построчно:

  • В первой строке мы указываем имя декоратора и то, что он принимает function в качестве своей переменной.
  • Вторая строка — это объявление функции-обёртки wrapper (). Тело обёртки в блоке состоит из трёх строк ниже. Оно как раз и описывает, что именно мы будем делать с функцией, ранее принятой декоратором.
  • Третья строка: записываем входящую переменную
    function ()
    в локальную переменную func. Здесь «локальная» означает, что она действует только в рамках функции wrapper ().
  • Четвёртая строка: мы применяем к func строковый метод upper и записываем результат в другую локальную переменную make_uppercase.

Больше локальных переменных богу локальных переменных! Конечно, всё это ради понятности и читаемости.

  • Пятая строка: функция wrapper () возвращает переменную make_uppercase, то есть строку от function (), но уже прописными буквами.
  • Последняя строка: декоратор возвращает нам уже саму функцию wrapper, точнее, результат её работы над функцией function.

Как это запустить? Пишем символ @, за ним название декоратора, а объявление функции say_hi переносим на строку под ней:

@uppercase_decorator
def say_hi():
    return 'всем привет'

Печатаем вывод декорированной функции:

print(say_hi())

Получаем на выходе:

ВСЕМ ПРИВЕТ

Если хочется немного дополнить, вот ещё примеры декораторов.

def logging(func):
    def log_function_called():
        print(f'Вызвана {func}')
        func()
    return log_function_called
@logging
def my_name():
	print('Крис')
@logging
def friends_name():
	print('Наруто')
 
my_name()
friends_name()
Источник

Что здесь происходит:

Декоратор принимает в качестве переменной функцию func

. Затем функция-обёртка log_function_called печатает «Вызвана func» и запускает её на выполнение. Функции my_name и friends_name печатают имена Крис и Наруто, а в обёрнутом виде декоратор предваряет их выполнение сообщением об их вызове.

def benchmark(func):
	import time
	def wrapper():
    	    start = time.time()
    	    func()
    	    end = time.time()
    	    print('[*] Время выполнения: {} секунд.'.format(end - start))
	return wrapper
@benchmark
def fetch_webpage():
	import requests
	webpage = requests.get('https://skillbox.ru')
	print(webpage)
fetch_webpage()
Источник

Что здесь происходит:

В объявлении декоратора benchmark мы импортируем библиотеку time. В функции-обёртке wrapper засекаем время в переменную start, затем выполняем полученную декоратором функцию, а после этого фиксируем время в переменную

end. Далее печатаем время выполнения, просто отняв от величины end величину start прямо внутри команды print.

Сама функция fetch_webpage делает простой GET-запрос на наш сайт. Для этого она импортирует популярную библиотеку requests, записывает в переменную webpage ответ сервера Skillbox на запрос и печатает эту переменную.

В обёрнутом виде декоратор «запускает секундомер», функция fetch_webpage делает запрос и печатает ответ, после чего декоратор «выключает секундомер» и печатает время, которое функция потратила на всю эту работу.

Если хотите произвести впечатление, то можно добавить, что:

  • Декоратор — это паттерн проектирования (design pattern) в Python, а также функция второго уровня, то есть принимающая другие функции в качестве переменных и возвращающая их.
  • И в сам декоратор, и в функцию-обёртку можно передать и позиционные, и именованные аргументы — args и kwargs соответственно.
  • Декораторы работают не только с функциями, но и с классами и методами.

Конечно, на собеседовании надо будет пояснить все эти пункты и проиллюстрировать их кодом. На курсе Профессия Python-разработчик вы изучите не только декораторы, но и всё необходимое для того, чтобы с блеском проходить любые собеседования.

Читайте также:

Vkontakte Twitter Telegram Скопировать ссылку

Учись бесплатно:
вебинары по&nbspпрограммированию, маркетингу и&nbspдизайну.

Участвовать

Против Microsoft подали иск на 9 млрд долларов за воровство кода для сервиса Copilot 11 ноя 2022

Хакеры заражали компьютеры с помощью клона графического редактора GIMP 10 ноя 2022

Дочерняя компания Cisco заблокировала российских пользователей и просит вернуть железо 08 ноя 2022

Понравилась статья?

Да

Decorators in Python — GeeksforGeeks

Decorators — очень мощный и полезный инструмент в Python, поскольку он позволяет программистам изменять поведение функции или класса. Декораторы позволяют нам обернуть другую функцию, чтобы расширить поведение обернутой функции, не изменяя ее навсегда. Но прежде чем углубиться в декораторы, давайте разберемся с некоторыми понятиями, которые пригодятся при изучении декораторов.

Объекты первого класса


В Python функции объекты первого класса , что означает, что функции в Python могут использоваться или передаваться в качестве аргументов.
Свойства функций первого класса:
  • Функция является экземпляром типа Объект.
  • Вы можете сохранить функцию в переменной.
  • Вы можете передать функцию в качестве параметра другой функции.
  • Вы можете вернуть функцию из функции.
  • Вы можете хранить их в структурах данных, таких как хэш-таблицы, списки и т. д.

Рассмотрим приведенные ниже примеры для лучшего понимания.

Пример 1: Обработка функций как объектов.

Python3

def shout(text):

     return text.

upper()

 

print (shout( 'Hello' ))

 

орать = орать

Печать (Yell ( 'Hello' ))

:

 Hello.
HELLO 

В приведенном выше примере мы присвоили функцию Shout переменной. Это не вызовет функцию, вместо этого он берет объект функции, на который ссылается крик, и создает второе имя, указывающее на него, крик.

Пример 2: Передача функции в качестве аргумента

Python3

def shout(text):

     return text. upper()

 

def whisper(text):

     Возврат Текст. Lelower ()

DEF GERET (FUNC):

GRETING =

=

9

0039 func( )

     print (greeting)

 

greet(shout)

greet(whisper)

Output:

 HI , Я СОЗДАН ФУНКЦИЕЙ, ПЕРЕДАВАЕМОЙ В КАЧЕСТВЕ АРГУМЕНТА. 
привет, меня создала функция, переданная в качестве аргумента. 

В приведенном выше примере функция приветствия принимает в качестве параметра другую функцию (в данном случае крик и шепот). Затем функция, переданная в качестве аргумента, вызывается внутри функции приветствия.

Пример 3: Возврат функций из другой функции.

Python3

 

def create_adder(x):

     def adder(y):

         return x + y

 

     возврат сумматор

 

add_15 = create_adder( 15 )

 

print (add_15( 10 ))

Output:

 25 

In the выше, мы создали функцию внутри другой функции, а затем вернули функцию, созданную внутри.
В приведенных выше трех примерах показаны важные понятия, необходимые для понимания декораторов. Пройдя через них, давайте теперь углубимся в декораторы.

Декораторы

Как указано выше, декораторы используются для изменения поведения функции или класса. В декораторах функции передаются в качестве аргумента другой функции, а затем вызываются внутри функции-оболочки.

Синтаксис декоратора:  

 @gfg_decorator
определение hello_decorator():
    печать("Гфг")
'''Приведенный выше код эквивалентен -
определение hello_decorator():
    печать("Гфг")
    
hello_decorator = gfg_decorator(hello_decorator)''' 

В приведенном выше коде gfg_decorator является вызываемой функцией, которая добавит некоторый код поверх какой-либо другой вызываемой функции, функции hello_decorator, и вернет функцию-оболочку.

Decorator can modify the behaviour :   

Python3

def hello_decorator(func):

 

    

    

      

    

    

     def inner1():

         печать 0( "Hello, this is before function execution" )

 

        

        

         func()

 

         print ( "This после выполнения функции" )

          

     return inner1 5

0002  

def function_to_be_used():

     print ( "This is inside the function !!" )

 

 

function_to_be_used = hello_decorator (function_to_be_used)

 

 

function_to_be_used()

функция до выполнения4, Вывод:

Это внутри функции !! Это после выполнения функции

Давайте посмотрим на поведение приведенного выше кода и на то, как он работает шаг за шагом при вызове «function_to_be_used».

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

Python3

Импорт Время

Импорт MATH

DEF 9

DEF 9

DEF 9.0040

      

    

    

    

     def inner1( * args, * * kwargs):

 

Начало = Время ()

func( * args, * * kwargs)

 

        

         end = time. time()

         Печать ( "Всего времени, взятого в:" , func .__ name__, End - начало)

Возврат

0039 inner1

 

 

 

@calculate_time

def factorial(num):

 

    

    

     time. sleep( 2 )

Печать (Математика. Факториал (NUM))

Фактор ( 10 ) 90 900 9003

Вывод:

 3628800
Общее время, затраченное на: factorial 2.0061802864074707 

Что, если функция что-то возвращает или функции передается аргумент?

Во всех приведенных выше примерах функции ничего не возвращали, поэтому проблемы не было, но возвращаемое значение может понадобиться.

Python3

def hello_decorator(func):

def inner1( * args, * * kwargs):

          

         print ( "before Execution" )

возвращался_value = Func ( * Args, * * kwargs)

         print ( "after Execution" )

          

        

         return returned_value

        

     возврат внутренний1

 

 

@hello_decorator

def sum_two_numbers(a, b):

     print ( "Inside the function" )

     return a + b

A, B = 1 , 2

Печать ( ". 0040

Вывод:

 перед выполнением
Внутри функции
после казни
Sum = 3 

В приведенном выше примере вы можете заметить большую разницу в параметрах внутренней функции. Внутренняя функция принимает аргумент как *args и **kwargs, что означает, что кортеж позиционных аргументов или словарь аргументов ключевого слова может быть передан любой длины. Это делает его общим декоратором, который может украшать функцию с любым количеством аргументов.

Цепочка декораторов

Проще говоря, цепочка декораторов означает украшение функции несколькими декораторами.

Example:  

Python3

def decor1(func):

     def inner():

         x = func ()

         возврат x * x

     return inner

 

def decor(func):

     def inner():

         x = Func ()

Возврат 2 * x

возврат

. 0040

 

@decor1

@decor

def num():

     return 10

 

print (num())

Вывод:

 400 

Вышеприведенный пример подобен вызову функции как –

 decor1(decor(num)) 

Как это сделать?

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

Декораторы в Python

В Python есть интересная функция под названием декораторы для добавления функциональности в существующий код.

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


Необходимые условия для обучения декораторов

Чтобы понять декораторы, мы должны сначала узнать несколько основных вещей в Python.

Нам должно быть комфортно с тем фактом, что все в Python (Да! Даже классы) является объектами. Имена, которые мы определяем, являются просто идентификаторами, привязанными к этим объектам. Функции не являются исключением, они тоже объекты (с атрибутами). Различные имена могут быть связаны с одним и тем же функциональным объектом.

Вот пример.

 по умолчанию сначала (сообщение):
    печать (сообщение)
первый("Привет")
второй = первый
второй ("Привет") 

Выход

  Привет
Hello  

Когда вы запускаете код, обе функции first и second дают одинаковый результат. Здесь имена first и second относятся к одному и тому же функциональному объекту.

Теперь все становится еще более странным.

Функции могут быть переданы в качестве аргументов другой функции.

Если вы использовали такие функции, как карта , фильтр и уменьшить в Python, то вы об этом уже знаете.

Такие функции, которые принимают другие функции в качестве аргументов, также называются функциями высшего порядка . Вот пример такой функции.

 по умолч. вкл.(х):
    вернуть х + 1
деф дек(х):
    возврат х - 1
def работать (функция, х):
    результат = функция (х)
    возвращаемый результат 

Мы вызываем функцию следующим образом.

 >>> работать(вкл.3)
4
>>> работать(дек,3)
2 

Кроме того, функция может возвращать другую функцию.

 по определению is_call():
    защита is_returned():
        распечатать("Привет")
    возврат is_returned
новый = is_вызванный ()
# Выводит "Привет"
новый() 

Вывод

  Привет  

Здесь is_returned() — это вложенная функция, которая определяется и возвращается каждый раз, когда мы вызываем is_call() .

Наконец, мы должны знать о замыканиях в Python.


Возвращаясь к декораторам

Функции и методы вызываются callable как их можно вызвать.

Фактически, любой объект, реализующий специальный метод __call__() , называется вызываемым. Таким образом, в самом общем смысле декоратор — это вызываемый объект, который возвращает вызываемый объект.

По сути, декоратор принимает функцию, добавляет некоторые функции и возвращает ее.

 по определению make_pretty(func):
    защита внутренняя():
        print("Меня наградили")
        функция()
    вернуться внутрь
обычный ():
    print("Я обычный") 

Когда вы запускаете следующие коды в оболочке,

 >>> обычный()
я обычный
>>> # украсим эту обычную функцию
>>> довольно = make_pretty(обычный)
>>> красивая ()
меня украсили
Я обычный 

В показанном выше примере make_pretty() является декоратором. На шаге присваивания:

 pretty = make_pretty(ordinary) 

Функция normal() была украшена, а возвращаемой функции было присвоено имя красивая .

Мы видим, что функция декоратора добавила некоторые новые функции к исходной функции. Это похоже на упаковку подарка. Декоратор действует как обертка. Характер украшенного предмета (настоящего подарка внутри) не меняется. Но теперь он выглядит красиво (так как он был украшен).

Как правило, мы украшаем функцию и переназначаем ее как

 обычный = make_pretty(обычный). 

Это обычная конструкция, и по этой причине в Python есть синтаксис, упрощающий ее.

Мы можем использовать символ @ вместе с именем функции-декоратора и поместить его над определением декорируемой функции. Например,

 @make_pretty
обычный ():
    print("Я обычный") 

эквивалентен

 def обычный():
    print("Я обычный")
обычный = make_pretty(ordinary) 

Это просто синтаксический сахар для реализации декораторов.


Декорирование функций параметрами

Приведенный выше декоратор был простым и работал только с функциями, у которых не было параметров. Что, если бы у нас были функции, принимающие такие параметры, как:

 по умолч. разделить(а, б):
    return a/b 

Эта функция имеет два параметра: a и b . Мы знаем, что это выдаст ошибку, если мы передадим b как 0.

 >>> делить(2,5)
0,4
>>> разделить(2,0)
Traceback (последний последний вызов):
...
ZeroDivisionError: деление на ноль 

Теперь давайте сделаем декоратор для проверки этого случая, который вызовет ошибку.

 по определению smart_divide(func):
    определение внутреннее (а, б):
        print("Я буду делить", а, "и", б)
        если б == 0:
            print("Упс! Делить нельзя")
            возвращаться
        функция возврата (а, б)
    вернуться внутрь
@smart_divide
Деф разделить (а, б):
    печать (а/б) 

Эта новая реализация вернет Нет , если возникнет ошибка.

 >>> разделить(2,5)
Я собираюсь разделить 2 и 5
0,4
>>> разделить(2,0)
Я собираюсь разделить 2 и 0
Упс! нельзя делить 

Таким образом мы можем декорировать функции, которые принимают параметры.

Внимательный наблюдатель заметит, что параметры вложенной функции inner() внутри декоратора совпадают с параметрами функций, которые он украшает. Принимая это во внимание, теперь мы можем делать общие декораторы, работающие с любым количеством параметров.

В Python эта магия выполняется как function(*args, **kwargs) . Таким образом, аргументов будет кортежем позиционных аргументов, а kwargs будет словарем аргументов ключевого слова. Примером такого декоратора будет:

 defworks_for_all(func):
    def внутренний (*args, **kwargs):
        print("Я могу украсить любую функцию")
        функция возврата (*args, **kwargs)
    return inner 

Объединение декораторов в цепочку в Python

Несколько декораторов могут быть объединены в цепочку в Python.

То есть функцию можно декорировать несколько раз разными (или одними и теми же) декораторами. Мы просто размещаем декораторы над нужной функцией.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *