Подтвердить что ты не робот

Динамические декораторы Python - почему так много оберток?

Итак, я все еще новичок в декораторах Python - я использовал их раньше, но я никогда не делал своего. Я читаю этот учебник (этот конкретный пункт), и я, похоже, не понимаю, зачем нам нужны три уровня функций? Почему мы не можем сделать что-то вроде этого:

def decorator(func, *args, **kwargs):
    return func(*args,**kwargs)

Спасибо:)

4b9b3361

Ответ 1

Хорошо, что произойдет, если вы назовете этот декоратор на функцию?

@decorator
def foo(): pass

Этот код немедленно вызовет foo, чего мы не хотим. Вызываются декораторы, и их возвращаемое значение заменяет эту функцию. Это то же самое, что сказать

def foo(): pass
foo = decorator(foo)

Итак, если у нас есть декоратор, который вызывает foo, мы, вероятно, хотим иметь функцию, которая возвращает функцию, которая вызывает foo - эта функция, которую он возвращает, заменит foo.

def decorator(f):
    def g(*args, **kwargs):
        return f(*args, **kwargs)
    return g

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

def argument_decorator(will_I_call_f):
    def decorator(f):
        def g(*args, **kwargs):
            if will_I_call_f: return f(*args, **kwargs)
        return g
    return decorator

поэтому мы можем сделать

decorator = argument_decorator(True)
@decorator
def foo(): pass

И Python предлагает удобный синтаксис, в котором вы встраиваете вызов функции:

@argument_decorator(True)
def foo(): pass

И все это синтаксический сахар для синтаксиса не-декоратора

def foo(): pass
foo = argument_decorator(True)(foo)

Ответ 2

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