简体   繁体   中英

Decorator of classes and functions

I have a problem with a Python decorator.

class decorator(object):
    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        print('sth to log: %s : %s' % (self.function.__name__, args))
        return self.function(*args, **kwargs)


@decorator
def sum_test(a, b):
    print('sum: %s' % (a+b))

@decorator
class Class_test(object):
    def __init__(self):
        pass
    def sum_func(self, a, b):
        print('class sum: %s' % (a+b))
        return a+b

if __name__ == '__main__':
    sum_test(3, 4)
    func = Class_test()
    var1 = func.sum_func(1, 4)
    print(var1)

Output:

sth to log: sum_test : (3, 4)
sum: 7
sth to log: Class_test : ()
class sum: 5
5

The decorator is working as I want for function sum_test . I can log that function sum_test was used with variables 3 and 4 .

I have a problem with decorating classes. I can log that object of class Class_test was created, but I don't have information that function sum_func was used.

Why is __call__() in decorator was not triggered when running sum_func on class object and it was triggered when used directly on function sum_test ?

Decorating the class with decorator means that Class_test is now a decorator object such that Class_test.function is the class you wrote a body for.

Remember, the @decorator syntax is syntactic sugar for

class Class_test(object):
    def __init__(self):
        pass
    def sum_func(self, a, b):
        print('class sum: %s' % (a+b))
        return a+b

Class_test = decorator(Class_test)

(Except that at no point does the Class_test symbol refer to your class).

So this decorator object is called when you call Class_test , which is exactly what you see happen in your log:

sth to log: Class_test : ()

func.sum_func , on the other hand, is a regular bound method. It doesn't know anything about decorator .

If you're going to use it inside classes, I would prefer a closure-style decorator (a function that returns a function). The function that it returns will get registered aa method normally by the class machinery.

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('sth to log: %s : %s' % (func.__name__, args))
        return func(*args, **kwargs)
    return wrapper

class Class_test(object):
    @decorator
    def sum_func(self, a, b):
        print('class sum: %s' % (a+b))
        return a+b

If you still want to use the class-based approach, read Python Class Based Decorator with parameters that can decorate a method or a function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM