Введение в концепцию декораторов

PythonPythonBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом разделе представляется концепция декоратора. Это продвинутая тема, которую мы только коснемся поверхностно.

Пример логирования

Рассмотрим функцию.

def add(x, y):
    return x + y

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

def add(x, y):
    print('Calling add')
    return x + y

Теперь вторая функция, также с некоторым логированием.

def sub(x, y):
    print('Calling sub')
    return x - y

Замечание

Замечание: Это несколько повторяющееся.

Написание программ, где есть много повторяющегося кода, часто действительно раздражает. Они утомительно трудны для написания и сложны для поддержки. Особенно если вы решаете, что хотите изменить, как это работает (например, другой вид логирования).

Код, который добавляет логирование

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

def logged(func):
    def wrapper(*args, **kwargs):
        print('Calling', func.__name__)
        return func(*args, **kwargs)
    return wrapper

Теперь используйте ее.

def add(x, y):
    return x + y

logged_add = logged(add)

Что происходит, когда вы вызываете функцию, возвращаемую функцией logged?

logged_add(3, 4)      ## Вы видите, что появляется сообщение о логировании

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

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

>>> logged_add(3, 4)
Calling add   ## Дополнительный вывод. Добавлен оберткой
7
>>>

Примечание: Функция logged() создает обертку и возвращает ее в качестве результата.

Декораторы

Оборачивать функции в обертки - это чрезвычайно распространенная практика в Python. Такая распространенность привела к появлению специального синтаксиса для этого.

def add(x, y):
    return x + y
add = logged(add)

## Особенный синтаксис
@logged
def add(x, y):
    return x + y

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

Комментарий

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

Упражнение 7.10: Декоратор для замера времени

Если вы определяете функцию, ее имя и модуль хранятся в атрибутах __name__ и __module__. Например:

>>> def add(x,y):
        return x+y

>>> add.__name__
'add'
>>> add.__module__
'__main__'
>>>

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

start = time.time()
r = func(*args,**kwargs)
end = time.time()
print('%s.%s: %f' % (func.__module__, func.__name__, end-start))

Вот пример того, как должен работать ваш декоратор:

>>> from timethis import timethis
>>> @timethis
def countdown(n):
    while n > 0:
        n -= 1

>>> countdown(10000000)
__main__.countdown : 0.076562
>>>

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

✨ Проверить решение и практиковаться

Резюме

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