Код
#статьи

Готовимся к собеседованию: что такое декораторы в Python

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

 vlada_maestro / shutterstock

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

— Расскажите, пожалуйста, про декораторы в 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 печатают имена Крис и Наруто, а в обёрнутом виде декоратор предваряет их выполнение сообщением об их вызове.

Измерение времени выполнения GET-запроса к серверу

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-разработчик вы изучите не только декораторы, но и всё необходимое для того, чтобы с блеском проходить любые собеседования.

Нейросети для работы и творчества!
Хотите разобраться, как их использовать? Смотрите конференцию: четыре топ-эксперта, кейсы и практика. Онлайн, бесплатно. Кликните для подробностей.
Смотреть программу
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована