Динамические декораторы Python - почему так много обёрток? - PullRequest
13 голосов
/ 23 апреля 2011

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

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

Спасибо:)

Ответы [ 2 ]

28 голосов
/ 23 апреля 2011

Что бы произошло, если бы вы вызвали этот декоратор для функции?

@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)
4 голосов
/ 23 апреля 2011

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

...