zoukankan      html  css  js  c++  java
  • day14装饰器

    1. 开放封闭原则:

      • 开放:对源码的拓展是开放的。
      • 封闭:对源码的修改是封闭的。
    2. 装饰器:完全遵循开放封闭原则,即在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。(装饰器的本质是闭包)

      • 举例:计算func1函数的运行效率。
      def func1():
          for i in range(10000):
              i+=1
      

      此问题相当于为函数func1增加一个方法,可以计算函数的运行时间。用简单的time模块就可以完成,如下:

      import time
      time.perf_counter()
      func1()
      print(f'程序运行的时间为:{time.perf_counter()}')
      

      但这样做不满足开放封闭原则,可更改为如下:

      import time
      def timer(f):
          def inner():
      		time.perf_counter()
              f()
              print(f'程序运行的时间为:{time.perf_counter()}')
          return inner
      func1=timer(func1)
      func1()   #这样在不改变原函数的调用方式下为原函数增加了新的功能。即为原始的装饰器模型。在运行大型平台时非常有用。
      
      #装饰器的本质是闭包
      import time
      def timer(f):
          f=func1   #f为自由变量,指向函数func1的内存地址。
          def inner():
      		time.perf_counter()
              f()
              print(f'程序运行的时间为:{time.perf_counter()}')
          return inner
      func1=timer(func1)
      func1() 
      

      但如果想要测试另一个函数(例如func3)的效率,则仍然需要增加一句语法:func3=timer(func3)。假设要测试的函数过多的话,就会比较麻烦。

    3. 原始装饰器模型的升级版本:python做了一个优化,提出了一个‘语法糖’的概念。即在编写了装饰器后,需要将装饰器代码放在所有代码的前方。

      import time
      #装饰器函数
      def timer(f):
          def inner():
      		time.perf_counter()
              f()
              print(f'程序运行的时间为:{time.perf_counter()}')
          return inner
      
      
      #当要对装饰器函数调用时,在要装饰函数的前方使用@+装饰器函数名,如下:
      
      
      @timer    #相当于func1=timer(func1)
      def func1():
          for i in range(10000):
              i+=1
              
      func1()
      
      
      #此时即使有func3,也可以直接在函数前调用装饰器:
      @timer      #会将两行并为一行读取:func3=timer(func3)
      def func3():
          pass
      
    4. 当函数有返回值时(被装饰函数有返回值时):

      import time
      #装饰器函数
      def timer(f):
          def inner():
      		time.perf_counter()
              f()
              print(f'程序运行的时间为:{time.perf_counter()}')
          return inner
      
      @timer
      def func1():
          for i in range(10000):
              i+=1
          return i
      print(func1())    #None,无法打印出函数func1的返回值。
      

      此时要对装饰器进行改进:

      import time
      #装饰器函数
      def timer(f):
          def inner():
      		time.perf_counter()
              r = f()    #将返回值赋值给r
              print(f'程序运行的时间为:{time.perf_counter()}')
              return r   #将返回值给inner函数。
          return inner
      
      @timer
      def func1():
          for i in range(10000):
              i+=1
          return i
      print(func1())     #10000
      

      加上装饰器不应该改变原函数的返回值,所有func1的返回值i应该返回给inner函数。

    5. 当函数有参数时(被装饰函数带参数):

      import time
      #装饰器函数
      def timer(f):
          def inner(*arg,**kargs):      #*的聚合
      		time.perf_counter()  
              r = f(*arg,**kargs)       #*的打散   ,并将返回值传给inner函数。
              print(f'程序运行的时间为:{time.perf_counter()}')
              return r   #将返回值给inner函数。
          return inner
      
      @timer
      def func1(num1,num2):
          for i in range(num1,num2):
              i+=1
          return i
      print(func1())     #
      
    6. 标准版的装饰器:

      def wrapper(f):
          def inner(*arg,**kargs):
              '''添加额外的功能:执行被装饰函数之前的操作'''
              ret = f(*arg,**kargs)
              '''添加额外的功能:执行被装饰函数之前的操作'''
              return ret
          return inner
      
      #装饰器的调用
      @wrapper
      def func():
          pass
      
    7. 装饰器的应用:

  • 相关阅读:
    整理一批 国内外优秀设计团队 & 设计相关网站
    国内技术团队博客盘点(不只是前端!)
    【技能大赛笔记01】Zigbee点对点按键控制程序开发
    【网络爬虫入门05】分布式文件存储数据库MongoDB的基本操作与爬虫应用
    【网络爬虫入门04】彻底掌握BeautifulSoup的CSS选择器
    【网络爬虫入门03】爬虫解析利器beautifulSoup模块的基本应用
    【网络爬虫入门02】HTTP客户端库Requests的基本原理与基础应用
    【网络爬虫入门01】应用Requests和BeautifulSoup联手打造的第一条网络爬虫
    【Zigbee技术入门教程-02】一图读懂ZStack协议栈的核心思想与工作机理
    【Zigbee技术入门教程-号外】基于Z-Stack协议栈的抢答系统
  • 原文地址:https://www.cnblogs.com/wby-110/p/12599806.html
Copyright © 2011-2022 走看看