用__call__ 实现装饰器功能

    之前我们用函数方式写了一个装饰器: https://blog.csdn.net/a545578125/article/details/79812878    但是Graham Dumpleton 和 Lennart Regebro 两位大神认为,装饰器最好通过实现 __call__ 方法的类实现,不应该通过函数实现。

    下面我们就来尝试一下用类实现装饰器:

import time
import functools


class T1:
    def __init__(self, name):
        self.name = name

    def __call__(self, func):
        print('I am outer!')

        @functools.wraps(func)
        def dec(*args, **kwargs):
            t0 = time.time()
            result = func(*args, **kwargs)
            elapsed = time.time() - t0
            name = func.__name__
            arg_lst = []
            if args:
                arg_lst.append(', '.join(repr(arg) for arg in args))
            if kwargs:
                pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
                arg_lst.append(', '.join(pairs))
            arg_str = ', '.join(arg_lst)
            print('[%0.8fs] %s(%s) -> %r ' % (elapsed, name, arg_str, result))
        return dec


@T1('test')
def t2():
    l = [1, 2, 3]
    ff = [x*x for x in l]
    print(ff)

t2()

输出:

I am outer!
[1, 4, 9]

[0.00000000s] t2() -> None 


        这里其实很好理解,因为T1('test')是T1的一个实例化对象,而这个对象因为实现了__call__方法,所以可以调用,这就和函数基本一样了。  也就是说,上述代码可以将@T1('test')改为  :

obj = T1('test')
@obj

    此处 T1('test') 中的 test  其实可以是任何字符串,因为这里只是进行了一次实例化,给self.name赋值。而不影响此实例的__call__方法。

完整代码:

import time
import functools


class T1:
    def __init__(self, name):
        self.name = name

    def __call__(self, func):
        print('I am outer!')

        @functools.wraps(func)
        def dec(*args, **kwargs):
            t0 = time.time()
            result = func(*args, **kwargs)
            elapsed = time.time() - t0
            name = func.__name__
            arg_lst = []
            if args:
                arg_lst.append(', '.join(repr(arg) for arg in args))
            if kwargs:
                pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
                arg_lst.append(', '.join(pairs))
            arg_str = ', '.join(arg_lst)
            print('[%0.8fs] %s(%s) -> %r ' % (elapsed, name, arg_str, result))
        return dec


obj = T1('test')
@obj
def t2():
    l = [1, 2, 3]
    ff = [x*x for x in l]
    print(ff)

t2()





阅读更多

没有更多推荐了,返回首页