装饰器

一、什么是装饰器

  器:指的是工具,可以定义成函数

  装饰:指的是被装饰对象添加新的工功能

  装饰器:指的是定义一个函数,所定义的这个函数是用来为其他函数添加新的功能

  装饰器的的实现原理:函数嵌套+闭包+函数对象的组合使用的产物

二、为什么需要装饰器

  软件的涉及应该遵循开发封闭原则

    开放:指的是对扩展功能是开放的

    封闭:指的是对修改源代码是封闭的

  用处:(为遵循开放封闭远程)在不修改源代码的情况下,需要对该功能进扩展,增加新的功能,这时就要用到装饰器

  例如:当一个软件已经发布使用后,并且运行很正常,如果需要增加新的功能(扩展该功能),这时如果在源代码的基础上进行修改增加功能后,有可能会出现想象不到的bug

     这个时候就不要去在源代码上进行增加功能了,就用到装饰器,在定义一个新的函数,定义的新的函数就是为其原来函数添加新的功能

 三、实现装饰器的过程

  def index(x,y):

    time.sleep(2)  # 等待2s执行下面的代码

    print(x,y)

  index(111,222)

  在不修改源代码的和调用方式的情况下,给该功能添加功能,计算代码的执行时间

  实现方式一:实现了计算执行代码的时间,没有修改调用方式,但是修改了源代码

    import time  # 导入一个函数,时间函数

    def index(x,y):

      start=time.time()  # 记录开始时间,time.time()是记录1970到现在的时间

      time.sleep(2)  # 等待2s在执行下面的函数

      print(x,y)

      stop=time.time()  # 记录结束时间

      print(stop-start)  # 计算执行的秒数

    index(111,222)

  实现方式二:没有修改源代码,也没有修改调用方式,但是代码“冗余”了,当有其他很多地方都调用了index函数时,就会出现重复代码

    import time  

    def index(x,y): 

      time.sleep(2)  

      print(x,y)

    start=time.time() 

    index(111,222)

    stop = time.time()

    print(stop-start)

  实现方式三:解决了代码“冗余”,没有对源代码进行修改,但是修改了调用方式,并且把index函数写死了,只能对index函数进行调用了

    import time  

    def index(x,y): 

      time.sleep(2)  

      print(x,y)

    def ouuter(*args,**kwargs):

      start=time.time() 

      index(*args,**kwargs)

      stop = time.time()

      print(stop-start)

    outer(111,222)

  实现方式四:使用闭包函数方式实现,没有修改源代码,也没有修改函数的调用方式,把index写活了,当遇到其他的函数也需要添加该功能时也可以直接进行调用

    import time  

    def index(x,y): 

      time.sleep(2)  

      print(x,y)

    def timer(func)   # func = index的内存地址

      def wrapper(*args,**kwargs):

        start=time.time() 

        func(*args,**kwargs)  # 把index换成了一个变量

        stop = time.time()

        print(stop-start)

      retrun wrapper

    index = timer(index)  

    index(111,222)

    # 如果还有其他函数也需要增加统计时间的功能,如有home函数

    def home(a,b,c):

      pritn(a,b,c)

    home=timer(home)

    home(3333.444.5555)

  实现方式五:如果该所调用的函数存在返回值,在方式四的基础上,为嵌套函数中的调用进行赋值,然后在进行返回

    def index(x,y):

      time.sleep(2)

      print(x,y)

      return  123 

    def timer(func):

      def wrapper(*args,**kwargs):

        start=time.time()

        res = func(*args,**kwargs)  # 给func函数调用赋值为res

        stop=time.time()

        print(stop-start)

        return res  # 返回res

      return wrapper

    index = timer(index)

    res = index(111,222)

    print(res)

  注意:实现方式五完全实现了在不修改源代码和调用方式的情况下给函数index增加一个执行时间的统计功能

     问题:但是在其他函数也需要用到这个功能的时候就需要重新进行如home = timer(home)的方式

  实现方式六:在以后函数需要调用装饰器时,不用在进行index = timer(index)

    def timer(func):

      def wrapper(*args,**kwargs):

        start=time.time()

        res = func(*args,**kwargs)  # 给func函数调用赋值为res

        stop=time.time()

        print(stop-start)

        return res  # 返回res

      return wrapper

    @timer  # 相当于 index = timer(index)

    def index(x,y):

      time.sleep(2)

      print(x,y)

      return  123 

    res = index(111,222)

    print(res)

  注意:在需要调用装饰器的上面加上@装饰器名字,表示一下函数调用该装饰器,但是装饰器必须写在调用之前

四、总结实现方式五和六,以后在为被装饰对象添加新功能时,可以进行用到装饰器

  装饰器方式是:

    def timer(func):

      def wrapper(*args,**kwargs):

        ``````````    #  中间为需要实现的代码

        res = func(*args,**kwargs)

        return res

      return wrapper

五、在使用装饰器后,当去查看原函数名或注释时,这里输出的为装饰器的函数名而不是原函数的名称或显示的注释,这是需要把装饰器和原函数伪造的更像需要加上functools

  示例如下    def auth(func):

        def inner(*args, **kwargs):
     return func(*args, **kwargs)
    return inner
    @auth
    def handler():
     pass
    handler()
    print(handler.__name__) # inner
  如上示例代码,当查handler的函数名时,其实看到的为inner函数(装饰器中的函数),这时需要把装饰器中的函数和原函数伪装的更像
  如下示例:
    import functools

    def auth(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
    return func(*args, **kwargs)
    return inner

    @auth
    def handler():
    pass
    handler()
    print(handler.__name__) # handler
  加上@functools.wraps(func)后,查看函数名或注释时都是现实为原函数,注意在以后的代码中,装饰器都加上该行代码

总结:结合上面四和五的示例代码,在以后写装饰器时都进行如下格式:
def auth(func):
@functools.wraps(func)
def inner(*args, **kwargs):
"""巴巴里吧"""      # 注释
res = func(*args, **kwargs) # 执行原函数
return res

return inner

posted @ 2021-01-24 01:13  A熙  阅读(117)  评论(0)    收藏  举报