Рубрики
Без рубрики

Развертывание декораторов, часть 1

Основы декораторов Python. Tagged с питоном, Pythonic, функциональным.

В более раннем посте я обещал поговорить о декораторах Python. Примечание для Smarty Pants, читающих это: по-видимому, есть что-то, что называется рисунком декоратора. В то время как вы можете использовать декораторы Python “Lower Crases D” для реализации рисунка декоратора, это лишь одно возможное использование для них. Для более длинного и более подробного обсуждения проблем именования здесь люди типа А должны прочитать соответствующие Pep Анкет Для остальной части этого поста, когда я говорю декоратор, я имею в виду функцию языка декоратора Python. В настоящее время. Впереди!

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

Функции как переменные

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

>>> a = "soup"
>>> b = 4
>>> def how_much_food(food, quantity):
...     return "I've got {} {}s!".format(quantity, food)
>>> gerald = how_much_food
>>> gerald(a, b)
"I've got 4 soups!"

Функции как параметры и возвращаемые значения

Круто, верно? Теперь, как прямой результат этого, вы можете выполнять функции в других функциях и вне других функций, как и любая другая переменная.

def call_this(f):
    f()
    print("Called it!")

def call_with_three(f):
    f(3)

def woof(times=1):
    return "Woof!" * times

>>> call_this(woof)
"Woof!"
"Called it!"
>>> call_with_three(woof)
"Woof!Woof!Woof!"

Определение функций в других функциях

Вы даже можете определить функции в других функциях! Это может быть супер мощный. Что приводит к одной из моих любимых головоломок за все время: сделайте следующий тестовый проход.

Утвердите пять (плюс (три ()))

def three(operator=None):
    if operator is None:
        return 3
    else:
        return operator(3)

def five(operator):
    if operator is None:
        return 5
    else:
        return operator(5)

def plus(second_number):
    def inner(first_number):
        return first_number + second_number
    return inner

# Get it?
# five(plus(three()))
# five(plus(3)) -> def inner: return first_number + 3
# five(inner) -> inner(5) -> 5 + 3 -> 8

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

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

Дерьмовый путь

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

def pre_bark(func):
    def inner():
        print("Woof!")
        return func()
    return inner

def hello():
    print("Hello!")

Чтобы обернуть Привет В функциональности вуфунг мы должны были бы сделать это:

>>> hello = pre_bark(hello)
>>> hello()
"Woof!"
"Hello!"

Вы видите, что происходит? Заменяем Привет с Внутренний , что печатает “Гауф!” Прежде чем называть оригинал Привет функция Не красиво. Не красиво, потому что вы должны обернуть Привет после того, как это определено. Кто -то мог бы взглянуть на определение функции, прежде чем называть ее, беспечно ожидая Привет! Но получение неожиданного Буд! . Путь наименее сюрприза, как правило, является лучшим. Что если это больше похоже на это:

Красивый путь

@pre_bark
def hello():
    print("Hello!")

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

Но как насчет моих аргументов?

Чтобы поймать любые аргументы, передаваемые вашей функции, внутренняя функция примет эти аргументы в форме *args, ** kwargs. Я не буду вдаваться в это сейчас, но это имеет довольно хорошее объяснение, если вы не знакомы. Краткая версия: воспринимайте *ARGS как список всех передаваемых позиционных аргументов, и ** Kwargs как о словаре всех принятых аргументов ключевых слов. Это не совсем точно, но это достаточно близко для государственной работы.

def print_them_args(func):

    def the_name_of_this_one_doesnt_matter(*args):
        print("{} called with {}".format(func.__name__, [*args]))
        return func(*args)
    return the_name_of_this_one_doesnt_matter

@print_them_args
def add(a, b):
    return a + b

>>> add(5, 8)
add called with [5, 8]
13

Я собирался продолжать, потому что нам все еще нужно поговорить о передаче аргументов декораторам, укладку декораторов, и мы даже не начал Чтобы покрыть то, что вы можете сделать с декораторами и занятиями! Но потом я посмотрел на свой словесный счетчик, который сообщил мне, что я был далеко за пределами самого смелого внимания. Я закончу с остальной частью этой следующей недели. Я уверен, что все будут смягчать кнопку обновления, с нетерпением жду драматического заключения.

Первоначально опубликовано мой блог .

Оригинал: “https://dev.to/rpalo/unwrapping-decorators-part-1”