user3132457
user3132457

Reputation: 1019

'NoneType' object is not callable with decorator class

I'm learning about decorator classes using this resource:
http://book.pythontips.com/en/latest/decorators.html#decorator-classes

The presented class is basically this:

class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile

    def __call__(self, func):
        log_string = func.__name__ + " was called"
        print(log_string)
        # Open the logfile and append
        with open(self.logfile, 'a') as opened_file:
            # Now we log to the specified logfile
            opened_file.write(log_string + '\n')
        # Now, send a notification
        self.notify()

    def notify(self):
        # logit only logs, no more
        pass

and the call:

@logit()
def myfunc1():
    pass

myfunc1()

I get an error:

>>> myfunc1()
[...]
TypeError: 'NoneType' object is not callable

Upvotes: 2

Views: 1512

Answers (1)

timgeb
timgeb

Reputation: 78700

logit.__call__ does return None, and you are doing myfunc1 = logit()(myfunc1) via decoration. myfunc is now None.

As far as I understand, you want to log each call of the decorated function. In this case, __call__ must build a new function and return it.

Something like

def __call__(self, func):
    def new_func(*args, **kwargs):
        log_string = func.__name__ + " was called"
        print(log_string)
        # Open the logfile and append
        with open(self.logfile, 'a') as opened_file:
            # Now we log to the specified logfile
            opened_file.write(log_string + '\n')
        # Now, send a notification
        self.notify()

        # execute func
        return func(*args, **kwargs)
    return new_func

Now

@logit()
def myfunc1():
    pass

does

myfunc1 = logit()(myfunc1)

i.e. it reassigns the name myfunc1 to the new function built in __call__. This new function does the logging-logic and then executes the old myfunc1 which it still holds onto under the name func as a closure variable.

Upvotes: 2

Related Questions