Ошибка декоратора: объект NoneType не вызывается

Я написал декоратор функций следующим образом:

def tsfunc(func):
    def wrappedFunc():
        print '%s() called' % func.__name__
        return func()
    return wrappedFunc()

@tsfunc
def foo():
    pass

foo()  # to get it work, use foo instead of foo()
foo()

Я получил следующее сообщение об ошибке:

foo() called
Traceback (most recent call last):
  File "decorator.py", line 11, in <module>
    foo()
TypeError: 'NoneType' object is not callable

Я получаю работу, заменяя "foo()" на "foo". но я все еще не получил ожидаемого результата:

foo() called

похоже, что функция foo вызывается только один раз.

Пожалуйста, помогите мне понять, почему это происходит.


person qinking126    schedule 26.01.2013    source источник


Ответы (3)


Вы должны вернуть саму функцию-оболочку, а не ее результат:

def tsfunc(func):
    def wrappedFunc():
        print '%s() called' % func.__name__
        return func()
    return wrappedFunc   # Do not call the function, return a reference instead

Декораторы заменяют декорированный элемент возвращаемым значением декоратора:

@tsfunc
def foo():
    # ....

эквивалентно:

def foo():
    # ....
foo = tsfunc(foo)

который расширяется до (в вашем коде):

foo = wrappedFunc()

поэтому вы заменяли функцию foo результатом вызова wrappedFunc(), а не самой wrappedFunc.

person Martijn Pieters    schedule 26.01.2013

Вам нужно убрать скобки в

return wrappedFunc

Предполагается, что декоратор возвращает функцию-оболочку, а не вызывает ее.

С этим исправлением код производит:

foo() called
foo() called
person NPE    schedule 26.01.2013

Немного поздно, но надеюсь, что это поможет. Расширяя информацию о том, почему предоставленный ответ принят

как указано в ошибке, «NoneType» означает, что экземпляр/объект, который мы пытаемся вызвать, не имеет типа (это не function/int/boolean/class/instance ). Его тип просто «Нет». Итак, резюмируя, декораторы — это не что иное, как расширенное использование замыканий с функциями, рассматриваемыми как граждане первого класса (вы можете получить подробное представление на замыкания Это в основном означает, что декоратор ожидает, что функция будет возвращена, скажем, в большинстве случаев обертка, при этом исходная функция не изменяется и вызывается декоратором.

def tsfunc(func):
    def wrappedFunc():
        print '%s() called' % func.__name__
        return func()
    return wrappedFunc() -> Here the function is not returned but called eventually

@tsfunc
def foo():
    pass

foo() - > calling this again doesnt make sense to trigger the decorator, since a reference for the method foo is enough. Hence foo works fine but foo() doesn't (method call has completed already but no value is returned) If you try like this, you would see that the variable has 'None' type

def tsfunc(func):
        def wrappedFunc():
            print '%s() called' % func.__name__
            return func()
        return wrappedFunc --  Here I made the correction
    
    @tsfunc
    def foo():
        pass
var1 = foo()
print(var1)

Это то, что произошло с вызовом foo(), когда у вас был неправильный способ вызова функции-оболочки, а не возврата только функции.

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

person vijayakumarpsg587    schedule 26.06.2020