Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator error: NoneType object is not callable

I wrote a function decorator like this:

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()

I got following error message:

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

I get it work by replacing "foo()" with "foo". but I still didn't get the result I expected:

foo() called

seems like the foo function is only called once.

Please help me understand why this is happening.

like image 933
qinking126 Avatar asked Jan 26 '13 10:01

qinking126


1 Answers

You should return the wrapper function itself, not its result:

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

Decorators replace the decorated item with the return value of the decorator:

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

is equivalent to:

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

which expands to (in your code):

foo = wrappedFunc()

so you were replacing the function foo with the result of the wrappedFunc() call, not with wrappedFunc itself.

like image 113
Martijn Pieters Avatar answered Sep 21 '22 20:09

Martijn Pieters