Комбинируем декораторы

Автор: CoolPython

Допустим, у нас есть функции, которые работают со строками. Возьмем, например, функцию, которая возвращает строчку из Zen of Python:

def readability():
    return 'Readability counts'

print(readability())
Readability counts

А теперь мы хотим, чтобы можно было показать текст в двух вариантах: жирным и курсивом. Вот два декоратора, один из которых добавляет тег <b>, а второй — <i> :

def bold(func):
    def wrapper():
        return '<b>' + func() + '</b>'
    return wrapper

def italic(func):
    def wrapper():
        return '<i>' + func() + '</i>'
    return wrapper

Как уже договаривались в прошлом посте, запись

@bold
def readable():
    return 'Readability counts'

Эквивалентна записи

readable = bold(readable)

И после применения декоратора вызов функции дает текст

print(readable())
Readability counts 

А что,если мы хотим получить текст одновременно и жирный, и с курсивом? Можно сделать композицию декораторов:

@italic
@bold
def readable():
    return 'Readability counts'
print(readable())
Readability counts

Обратите внимание, что результат в зависимости от порядка применения декораторов будет разным:

@bold
@italic
def readable():
    return 'Readability counts'
print(readable())
Readability counts

Так получается из-за разного порядка выполнения функций: в первом случае мы сначала добавляем тэг <b>, а сверху оборачиваем в <i>:

readable = italic(bold(readable))

А во втором — наоборот:

readable = bold(italic(readable))

Читаемость имеет значение! И порядок тоже.