Любопытно, что переводчик делает здесь - PullRequest
0 голосов
/ 09 сентября 2018

Я работал над учебным пособием по шаблону оформления (кредит Jungwoo Ryoo)

Мне любопытно, почему я могу поменять строки: return decorator и print(hello_world()) с return decorator() и print(hello_world)

from functools import wraps

def make_blink(function):
    """Defines the decorator"""

    @wraps(function)
    # Define the inner function
    def decorator():

        # Grab the return value of the function being decorated
        ret = function()
        # Add new functionality to the function being decorated
        return "<blink>"+ ret + "<b/link>"
    return decorator #return decorator()#<THIS LINE HERE SWAPPED

# Apply the decorator here!
@make_blink
def hello_world():
    """Original function! """

    return "Hello, World!"

# Check the result of decorating
print(hello_world()) #print(hello_world) #<THIS LINE HERE SWAPPED

Разве переводчик не будет делать что-то другое каждый раз? Я просто хочу понять, чтобы лучше понять, что происходит

1 Ответ

0 голосов
/ 09 сентября 2018

Декораторы - это просто функции , а функции - это просто объекты.

Линии

@make_blink
def hello_world():
    # ...

по сути такие же, как

def hello_world():
    # ...
hello_world = make_blink(hello_world)

за исключением того, что функциональный объект никогда не присваивается hello_world первым (он находится в стеке для передачи декоратору).

Так что все, что вы возвращаете из make_blink(), присваивается обратно hello_world. Это может быть функциональный объект, но это может быть и нечто совершенно иное.

Поэтому, когда вы используете return decorator, вы указываете Python установить hello_world для объекта вложенной функции. Когда вы используете return decorator(), вы указываете Python использовать результат функции decorator(). Здесь это строковое значение. Это как если бы вы сделали это:

def hello_world():
    """Original function! """
    return "Hello, World!"

hello_world = "<blink>" + hello_world() + "</blink>"

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

Но что, если вы изменили исходное тело функции hello_world(), чтобы оно возвращало каждый раз что-то новое? Что если бы у вас было:

import random

@make_blink
def random_greeting():
    return 'Hello ' + random.choice('DonAr', 'Martijn Pieters', 'Guido van Rossum') + '!'

Теперь имеет значение большое , что вы возвращаете из make_blink() звонка! Для верхнего уровня модуля декораторы выполняются только один раз при импорте. Если бы вы использовали return decorator(), вы бы запустили random.choice() только один раз, и у вас было бы фиксированное значение random_greeting для одного статического строкового результата.

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

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

...