系统学习Python——装饰器:函数装饰器-[添加装饰器参数:基础知识]

分类目录:《系统学习Python》总目录


前面文章介绍的计时器装饰器有效运行,但是如果它可配置性更强的话,就会更好一一一例如提供一个输出标签并且可以打开或关闭跟踪消息,这些在一个多用途工具中可能很有用。装饰器参数在这里派上了用场:对它们适当编写后,我们可以使用它们来指定配置选项,每个被装饰的函数都可以有各自的选项。例如,可以像下面这样添加标签:

import time
def timer(label=''):
    def decorator(func):
        def onCall(*args):
            start = time.perf_counter()
            func(*args)
            print(label, time.perf_counter() - start)
        return onCall
    return decorator

@timer('===')
def listcomp(N):
    return [x * 2 for x in range(N)]

输入:

listcomp(100)

输出:

=== 3.160000778734684e-05

这段代码添加了一个外层作用域来保存装饰器参数,以便随后真正调用的时候使用。当定义listcomp函数的时候,Python实际上调用了decorator(在真正装饰发生之前运行的timer的返回结果),其外层作用域内有着可用的值。也就是说,timer返回的装饰器,它既记住了装饰器参数又记住了最初的函数,并且返回一个可调用的onCall函数,最终这个函数在随后调用时调用最初的函数。因为这一结构创建了新的decoratoronCall函数,它们的外层作用域保留的状态与具体的装饰器相关。

我们可以把这种结构用于计时器之中,这样就能在装饰的时候传人一个标签和一个跟踪控制标志。下面是这么做的一个例子,我们可以将其编写在了一个模块文件中,以便它可以作为一个通用工具导人;它为第二个状态保留层使用了类而不是嵌套丞数,但是总的结果是相似的:

import time
def timer(label='', trace=True):
    class Timer:
        def __init__(self, func):
            self.func = func
            self.all_time = 0

        def __call__(self, *args, **kargs):
            start = time.perf_counter()
            result = self.func(*args, **kargs)
            elapsed = time.perf_counter() - start
            self.all_time += elapsed
            if trace:
                print('%s: %f, %f' % (self.func.__name__, elapsed, self.all_time))
            return result
    return Timer

我们在这里主要是把最初的Timer类嵌人一个外层函数中,以便创建一个依照不同的部署保持装饰器参数的作用域。外层的timer函数在装饰发生前调用,并且它只是返回Timer类作为实际的装饰器。在装饰时,创建了Timer的一个实例,它记住被装饰函数自身,而且还能访问位于外围函数作用域中的装饰器参数。

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.

你可能感兴趣的:(系统学习Python,Python,python,装饰器,函数,类,对象,方法)