• 概念:在函数中(嵌套)定义另一个函数时,内部函数引用了外层函数的名字。
  • 特性

    • 闭包函数必须在函数内部定义
    • 闭包函数可引用外层函数的名字

闭包函数是函数嵌套、函数对象、名称空间与作用域结合体

闭包中被内部函数引用的变量,不会因为外部函数结束而被释放掉,而是一直存在内存中,直到内部函数被调用结束

  1. # 闭包函数的定义
  2. def func(y):
  3. x = 100
  4. def inner(): # 此处的inner 就是闭包函数
  5. print(x)
  6. print(y)
  7. return inner
  8. # 闭包函数的调用
  9. inner = func(1000)
  10. inner()
  • 应用:为了给装饰器的使用做准备

  • 概念:在不修改被装饰对象源代码与调用方式的前提下,添加新的功能。简单来说,就是给其他函数增加额外功能的函数
  • 装饰器必须遵循“开放封闭”原则
    • 开放:对函数功能的添加是开放的
    • 关闭:对函数功能的修改是封闭的
  • 必备条件

    • 不能改变被装饰对象源代码
    • 为被装饰对象添加新的功能
    • 不能改变被装饰对象调用方式
  • 使用装饰器,可以解决代码冗余问题,提高代码的可扩展性
  • 应用:统计时间、登录认证

说了这多理论,上代码。

需求:统计下载媒体文件的时间(简易版)

  1. # 需求: 统计下载电影的时间。
  2. # 一般我们实现这个功能的方式如下
  3. import time
  4. def download_movie():
  5. """
  6. 下载电影功能
  7. :return: None
  8. """
  9. print("电影下载开始了……")
  10. time.sleep(2) # 模拟电影下载2 秒
  11. print("下载完成")
  12. start_time = time.time() # 获取当前时间戳
  13. download_movie() # 下载电影
  14. end_time = time.time() # 获取当前时间戳
  15. print(f"下载时间:{end_time-start_time}")

以上代码确实实现了统计下载时间的功能,问题来了,如果我有多个类型文件下载函数,都需要统计时间呢?难道展现我们的“CV大法”?估计隔天就要被扫地出门了……

就没有什么办法可以解决了吗?当然有啦!先看代码

  1. # 定义一个装饰器
  2. def time_record(func):
  3. """
  4. 新增统计时间功能
  5. :param func: 使用该功能的函数对象
  6. :return: inner 函数对象
  7. """
  8. def inner():
  9. # 统计开始
  10. start_time = time.time()
  11. func() # func() ----→ download_movie() or download_music()
  12. end_time = time.time()
  13. # 统计结束,打印统计时间
  14. print(f"下载时间:{end_time-start_time}")
  15. return inner
  16. def download_movie():
  17. """
  18. 模拟下载电影
  19. :return: None
  20. """
  21. print("电影下载开始了……")
  22. time.sleep(2)
  23. print("下载完成!")
  24. def download_music():
  25. """
  26. 模拟下载音乐
  27. :return: None
  28. """
  29. print("歌曲下载开始了……")
  30. time.sleep(2)
  31. print("下载完成!")
  32. # time_record(download_movie) 返回一个inner,将其赋值给download_movie
  33. inner = time_record(download_movie)
  34. inner() # inner() ----→ download_movie()
  35. # time_record(download_music) 返回一个inner,将其赋值给download_music
  36. inner1 = time_record2(download_music)
  37. inner1()

以上代码就是对装饰器的引入,其中 time_record 就是装饰器,download_moviedownload_music 就是被装饰的函数对象。

通过观察

版权声明:本文为xiaodan1040原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xiaodan1040/p/11843329.html