浅谈python装饰器

概念

基本概念

python装饰器是一种用于拓展原有函数功能的一种函数

功能

python装饰器的返回值也是一个函数,它可以提取大量函数中与本身无关的类似代码,从而实现代码复用,
而且还能将函数和类的功能扩充,实现被装饰对象的功能扩展。

应用场景
  • 插入日志
  • 性能测试
  • 事务处理
  • 权限校验
  • 缓存

闭包与装饰器

闭包:在函数中嵌套一个函数,并且引用外部函数的变量。

def outer(x):
    def inner(y):
        return x + y
    return inner

print(outer(1)(2))
------------------
>>>3

装饰器实际上是闭包的一种应用
装饰器就是对函数(方法)或者的功能进行扩充,然后将扩充的方法或者再返回。

装饰器的编写与使用

无参数的装饰器

编写一个统计函数运行花费的时间的装饰器如下

def cost_time(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f'---总共花了{round(end_time - start_time, 2)}秒---')
    return wrapper

被装饰的函数如下

@cost_time
def sleeping():
    for i in range(3):
        s = random.randint(1, 4)
        print(f'sleeping {s} seconds...')
        time.sleep(s)

sleeping()

执行的结果

sleeping 2 seconds...
sleeping 1 seconds...
sleeping 3 seconds...
---总共花了6.0秒---
带参数的装饰器

依然是时间装饰器,修改上面的代码如下

def cost_time(parameter):
    def cost_time_inner(func):
        def wrapper(*args, **kwargs):
            print(parameter)  # 装饰器的参数
            start_time = time.time()
            func(*args, **kwargs)
            end_time = time.time()
            print(f'---总共花了{round(end_time - start_time, 2)}秒---')
        return wrapper
    return cost_time_inner

被装饰的函数如下

@cost_time('---开始计时---')
def sleeping():
    for i in range(3):
        s = random.randint(1, 4)
        print(f'sleeping {s} seconds...')
        time.sleep(s)

结果如下

---开始计时---
sleeping 4 seconds...
sleeping 3 seconds...
sleeping 1 seconds...
---总共花了8.0秒---

相比上面的无参数装饰器多输出一句“开始计时”的话,这句话就是装饰器传递的参数。

类装饰器

装饰器除了可以用函数写,也可以用类来写,其用法与函数装饰器没有太大区别,实质上是用了类方法中的call方法来实现类的直接调用。

我们同样编写一个统计时间的类装饰器

class CostTime:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start_time = time.time()
        self.func()
        end_time = time.time()
        print(f'---总共花了{round(end_time - start_time, 2)}秒---')

被装饰的函数如下

@CostTime
def sleeping():
    for i in range(3):
        s = random.randint(1, 4)
        print(f'sleeping {s}...')
        time.sleep(s)

结果如下

sleeping 2...
sleeping 1...
sleeping 3...
---总共花了6.0秒---

可以看到,运行的过程和结果都跟无参数的装饰器差不多。同样类装饰器也可以带有参数,有兴趣的小伙伴可以自己尝试一下。

总结

好了,以上就是装饰器的一些概念和大概用法,想深入了解装饰器的话还是需要在平常多练习和应用中体会。

posted @ 2020-07-02 14:29  蓝莓薄荷  阅读(205)  评论(0编辑  收藏  举报