• Python学习基础笔记十九——装饰器


    装饰器的形成过程:

    1. import time
    2. def func1():
    3. print('in func1')
    4. start = time.time()
    5. func1()
    6. end = time.time()
    7. print(end - start)

    再进一步:

    1. import time
    2. def timer(f): # 计算函数执行时间,将函数名作为参数
    3. start = time.time()
    4. f() # 执行函数
    5. end = time.time()
    6. print(end - start)
    7. def func():
    8. print("Hello world!")
    9. timer(func)

    第二次进化:

    1. import time
    2. def func():
    3. print("Hello world!")
    4. def timer(f): # 装饰器
    5. def inner(): # 闭包
    6. start = time.time()
    7. f() # 被装饰器函数
    8. end = time.time()
    9. print(end - start)
    10. return inner
    11. func = timer(func)
    12. func()

    说明程序的运行过程:

    第一步:def func():  func函数声明

    第二步:def timer(func)  timer函数声明

    第三步:func = timer(func)  先运行timer函数,传递func函数名(内存地址)

    第四步:def inner():开始运行timer函数内部代码,声明inner函数

    第五步:return inner: 返回inner内存地址

    第六步:func = timer(func):  将timer的返回值(inner内存地址)传给func变量(实际也是内存地址,跟func函数的内存地址是一样的

    第七步:func() 开始执行func(),实际上执行的就是inner函数,因为将inner内存地址赋值给了func变量的内存地址。

    第八步:start = time.time(), 开始到inner函数内部开始执行,从这步开始,获得当前系统时间赋值给start变量。

    第九步:f(), 开始执行f函数,该f,就是上一层timer函数传递进来的参数func。

    第十步:print("Hello world!")然后执行func函数内部代码,执行完毕,即退出func函数。

    第十一步:end = time.time(), 获得当前系统时间,赋值给end变量。

    第十二步:print(end - start), 然后获得两个时间时间差,并打印,到这一步,inner函数执行完毕,退出inner。

    第十三步:到func()调用函数的下一行。

    装饰器的作用:

    不想修改函数的调用方式,但是还想在原来的函数的前后添加新功能,timer是一个装饰器函数,只是对一个函数有一些装饰作用。

    从上面的代码可见,timer是装饰器函数,f() 是被装饰的函数。

    进一步变化:

    1. import time
    2. def timer(f):
    3. def inner():
    4. start = time.time()
    5. f()
    6. end = time.time()
    7. print(end - start)
    8. return inner
    9. @timer # 装饰器函数名
    10. def func(): # 被装饰的函数名
    11. print("Hello world!")
    12. # func = timer(func)
    13. func()

    注意其中的@timer的位置。

    再进一步,注意其中对返回值的处理:

    1. import time
    2. def timer(f):
    3. def inner():
    4. start = time.time()
    5. ret = f()
    6. end = time.time()
    7. print(end - start)
    8. return ret
    9. return inner
    10. @timer # 装饰器函数名
    11. def func(): # 被装饰的函数名
    12. print("Hello world!")
    13. return '新年好'
    14. # func = timer(func)
    15. ret = func()
    16. print(ret)

    如果func有返回值,看看装饰器函数timer中是怎么处理的,然后调用的时候也要注意下这个返回值。

    再进一步:

    1. import time
    2. def timer(f):
    3. def inner(a):
    4. start = time.time()
    5. ret = f(a)
    6. end = time.time()
    7. print(end - start)
    8. return ret
    9. return inner
    10. @timer # 装饰器函数名
    11. def func(a): # 被装饰的函数名
    12. print("Hello world!", a)
    13. return '新年好'
    14. # func = timer(func)
    15. ret = func(1)
    16. print(ret)

    装饰带参数函数的装饰器。有了对带参数的处理。

    进一步变化, 万能参数:

    1. import time
    2. def timer(f):
    3. def inner(*args, **kwargs):
    4. start = time.time()
    5. ret = f(*args, **kwargs)
    6. end = time.time()
    7. print(end - start)
    8. return ret
    9. return inner
    10. @timer # 装饰器函数名
    11. def func(a): # 被装饰的函数名
    12. print("Hello world!", a)
    13. return '新年好'
    14. @timer # 装饰器函数名
    15. def func(a, b): # 被装饰的函数名
    16. print("Hello world!", a, b)
    17. return '新年好'
    18. # func = timer(func)
    19. ret = func(1)
    20. print(ret)

    最后,我们再将装饰器简化:

    1. def wrapper(f): # 装饰器wrapper
    2. def inner(*args, **kwargs):
    3. '''在装饰前要做的事情'''
    4. ret = f(*args, **kwargs) # 被装饰的函数
    5. '''在装饰后要做的事情'''
    6. return ret
    7. return inner
    8. @wrapper # 装饰器函数名
    9. def func(a, b): # 被装饰的函数

    这个就是一个装饰器固定模式。

    原则:开放封闭原则:

    开放:对扩展是开放的。

    封闭:对修改是封闭的。

    目的是维护代码的稳定性,那么这个就是装饰器存在的意义。

  • 相关阅读:
    C语言基础练习题11-20
    excel提取单元格中的数字
    vue新手入门之使用vue框架搭建用户登录注册案例,手动搭建webpack+Vue项目(附源码,图文详解,亲测有效)
    知行合一
    隔离这几天开发了一个带控制台的OAuth2授权服务器分享给大家
    k8s 中 Pod 的控制器
    线性代数知识点总结(下)
    MFC Windows 程序设计[136]之文件属性统计(附源码)
    Echarts 3D饼图开发
    测试踩坑 - 当已有接口(或数据库表中)新增字段时,都需要注意哪些测试点?
  • 原文地址:https://blog.csdn.net/chang_chunhua/article/details/128168171