zoukankan      html  css  js  c++  java
  • Python入门之函数的装饰器

    本章目录:

        装饰器:

            一、为什么要用装饰器

            二、什么是装饰器

            三、无参装饰器

            四、装饰器语法糖

            五、认证装饰器实现

            六、叠加多个装饰器

            七、带参装饰器   

    ===========================================================

     

    一、开放封闭原则

      引子--为什么要用装饰器

      软件一旦上线后,对修改源代码是封闭的,对功能扩展是开放的。

      也就是说我们必须找到一种解决方案:

        能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能

        

        总结,原则如下:

          1、不修改源代码

          2、不修改调用方式

        目的:

          在原则1&2的基础上扩展新功能

    二、什么是装饰器

      装饰器(Decorator)是一种特殊的函数,用来给函数添上新功能的函数。

      主要用于抽离大量函数中与函数本身无关的雷同代码并继续重用。

      装饰器又可分为带参数和不带参数。

      完整含义:

      装饰器即在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能

     

      装饰器与被装饰对象均可以是任意可调用的对象

     

      装饰器>>>函数

      被装饰的对象>>>函数

    三、装饰器实现之无参装饰器

      装饰器的实现不能脱离,不能修改源代码,不能修改源调用方式的原则。下面我们将按照实现装饰器的思路,一步一步实现装饰器。

      为下面的程序增加运行计时功能。

    import time
    
    def index():
        
       time.sleep()
       print('This is Index Page!')    

      方案1:

    import time
    
    def index():
        start_time=time.time()
        time.sleep(3)
        print('welcome to index page')
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
    
    index()
    # 该方案虽然达到了计时功能,但是修改了源代码,违背了装饰器两大原则

       方案2:

    import time   #引入时间包,方便调用time()方法
    
    
    def index():
        time.sleep(2)
        print('This is Index Page.')
    
    
    start_time = time.time()
    index()
    stop_time = time.time()
    print('The running time is %s' % (stop_time - start_time)
    # 该方案虽然达到了计时功能,但是只是针对的增加代码,如果别的程序也要计时,还要重写一次,无法复用。

      方案3:

    import time
    
    
    def index():
        time.sleep(2)
        print('This is Index Page')
    
    
    def wrapper():
      start_time = time.time()
      index()
      stop_time = time.time()   
      print('The running time is %s' % (stop_time - start_time)) 
    # 该方案虽然达到了计时功能,但是要显示计时,还要去调用wrapper(),更改了原函数的调用方式

      方案4:

    import time
    
    
    def index():
        time.sleep(2)
        print('This is Index Page')
    
    
    def wrapper(func):    #func = index
        
        start_time = time.time()
        func();      #index
        stop_time = time.time()
        print('The running time is %s' % (stop_time, start_time))
    
    
    wrapper(index)
    # 该方案虽然达到了计时功能,但是要显示计时,不仅要调用wrapper(), 而且需要把原函数index作为参数导入,更改了原函数的调用方式

      方案5(步入正轨之无参装饰器):

    import time
    
    
    def index():
        time.sleep()
        print('This is Index Page')
    
    
    def outter(func):     # func = 最初始的index
                          # func = index    巧用闭包,传递参数,
                          # 外部函数带的参数,就是准备给内部函数里用的,这里是闭包功能
        def wrapper(): 
            start_time = time.time()
            func()
            stop_time = time.time()
            print('The running time is %s')
        return wrapper
    
    index = outter(index)   #初始index函数经过处理已经被变更为outter(index),被''装饰''了
    
    index()
    # 该方法能显示运行时长, 是把最初始的index函数通过闭包的特点,经过处理后重新把新的函数内存地址,赋值给了index,后面的index函数已经不是最初的index,它经过被''装饰''了

      方案6(方案5的升级版):

        1. 无参装饰器,引入带参函数的时候出现了错误。

    # 不同于index()函数,这次我们引入一个新函数,带参数call_you(name)
    import time
    
    
    def call_you(name):
        time.sleep(2)
        print('I call you %s' %name)
    
    def outter(func):
        
        def wrapper(name):
            start_time = time.time()
            res = func(name)
            stop_time = time.time()
            print('The running time is %s' % (stop_time - start_time)
            return res
    
        return wrapper
    
    index = outter(index)
    home = outter(home)  #home带参,但是index不带参,这里运行会报错

      方案7(解决方案6的问题):

    # 运用可变长度参数处理这个问题
    # 可变长度参数模版,注意参数是*args  **kwargs
    
    def outter(func):
    
        def inner(*args, **kwargs):
            res = func(*args, ** kwargs)
            return res
    
        return inner
    import time
    
    
    def call_you(name):
        time.sleep(2)
        print('I call you %s' %name)
    
    
    def outter(func):
    
            def wrapper(*args, **kwargs):
                start_time = time.time()
                res = func(*args, **kwargs)
                stop_time = time.time()
                print('The running time is %s' %(stop_time - start_time))
                return res
            return wrapper
    
    call_you
    = outter(call_you) call_you('Puppy')

    四、装饰器语法糖

      语法糖意指那些没有给计算机添加新功能,只是对人类来说更加“甜蜜”的语法,能够增加程序的可读性,减少代码出错的机会。

    # 注意语法糖的放置位置,放在要用的函数的顶部,要用@开头

     

     

    五、认证装饰器实现

      1. 加入认证模块的简单实现:

     

      2. 加入认证模块后登陆进行验证:

     

    六、叠加多个装饰器
    # 注意多个装饰器的顺序,按照顺序执行

      1. 认证装饰器

      

      2. 计时装饰器

      

      3. 叠加多个装饰器(注意先后顺序)

    七、带参装饰器
     
    带参数,可以让装饰器有更大的灵活性。上面写的无参装饰器唯一的参数就是执行对应的业务函数。装饰器的语法允许我们在调用的时候,提供其他参数。新增的参数为装饰器的编写和使用提供了更大的灵活性
     
     
    上面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的 一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。
    当我们调用的时候,Python能够发现这一层封装,并把参数传递到装饰器的环境中。
  • 相关阅读:
    SAP ABAP Netweaver服务器的标准登录方式讲解
    php导出百万数据到csv
    消息中间件Kafaka
    kafka安装
    Linux系统下安装jdk及环境配置(两种方法)
    PHP导出3w条数据成表格
    excel 导出导入
    利用Redis锁解决高并发问题
    BeyondCompare4破解方法
    Linux(Ubuntu)通过nfs挂载远程硬盘
  • 原文地址:https://www.cnblogs.com/JetpropelledSnake/p/8671220.html
Copyright © 2011-2022 走看看