Ошибка декоратора: объект 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
Функция вызывается только один раз.
Пожалуйста, помогите мне понять, почему это происходит.
4 ответа
Вы должны вернуть саму функцию-обертку, а не ее результат:
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
сам.
Вы должны удалить скобки в
return wrappedFunc
Декоратор должен возвращать функцию-обертку, а не вызывать ее.
С этим исправлением код выдает:
foo() called
foo() called
Немного поздно, но надеюсь, что это поможет, Продолжая объяснять, почему предоставленный ответ принят
в сообщении об ошибке "NoneType" означает, что экземпляр / объект, который мы пытаемся вызвать, не имеет типа (это не функция /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(), когда у вас был неправильный способ вызова функции-оболочки вместо возврата только функции
Таким образом, чтобы декоратор функционировал в соответствии с нормами, он должен возвращать функцию-оболочку с неизмененной исходной функцией. И, следовательно, его следует переписать в соответствии с принятым ответом
вы используете этот синтаксис
def tsfunc(func):
def wrappedFunc():
print '%s() called' % func.__name__
return func()
return wrappedFunc # not use wrappedFunc() becaues Because this function runs at the this time
@tsfunc
def foo():
pass
foo() #