Python: нам действительно нужны обертки для декораторов?(Revisited) - PullRequest
0 голосов
/ 19 июня 2019

A аналогичный вопрос был задан, но OP сравнивает оболочку с функцией без возврата, поэтому ответы сосредоточены на этой "ошибке".
Я понял декораторы и почему мы их используем вместоподклассов после прочтения этой статьи .Там они пишут следующий пример, в котором вводят необходимость в оболочке:

def uppercase_decorator(function):
    def wrapper():
        funct = function()
        make_uppercase = funct.upper()
        return make_uppercase

    return wrapper

Тем не менее, я могу написать «то же самое» (я ожидаю, что вы скажете, что это не так), этоway:

def uppercase_decorator(function): #previously 'function' was called 'message' but 'function' is clearer for comparison. 
    make_uppercase = function().upper
    return make_uppercase

Обе версии могут быть применены к этому fn, что приведет к тому же выводу ('HI ALL!') при вызове salute():

@uppercase_decorator
def salute():
    return 'Hi all!'

Если основной fnвозвращает случайную строку (спасибо @wim за подсказку), можно заметить, что каждый раз, когда она запускается, строка без оболочки всегда возвращает одно и то же при выполнении строки sayGarbage():

def decorateIt(fn):
    toUpper = fn().upper  
    return toUpper  

def decorateW(fn):  
    def wrapper():  
        funct = fn()  
        toUpper = funct.upper()  
        return toUpper  
    return wrapper  

import random, string  

@decorateIt  
def sayGarbage():  
    return "".join(random.choice(string.ascii_lowercase) for i in range(6))  

sayGarbage()

Почемучто так?

1 Ответ

3 голосов
/ 19 июня 2019

Давайте посмотрим, что здесь происходит:

def uppercase_decorator(message): 
    make_uppercase = func().upper
    return make_uppercase

@uppercase_decorator
def salute():
    return 'Hi all!'
  • Во-первых, uppercase_decorator определяется.
  • Во-вторых, salute определяется.
  • В-третьих, uppercase_decorator получает с именем , передавая функциональный объект salute вместо первого позиционного аргумента (message).

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

Нужны ли нам обертки для декораторов?

Нет. Можно писать декораторы в более приятном стиле «без замыканий», как вы предлагаете, но не так. Если вы хотите написать декоратор без вложенной функции, попробуйте вместо этого использовать популярную библиотеку decorator.py. Это будет выглядеть так:

from decorator import decorator

@decorator
def uppercase_decorator(func, *args, **kwargs):
    result = func(*args, **kwargs)
    return result.upper()
...