zoukankan      html  css  js  c++  java
  • python之路--装饰器

    一.什么是装饰器

      首先,让我们在字面上来理解。装饰,即添加额外的修饰,在不改变函数源代码和调用方式的前提下,添加额外的功能。器,在python里面,指定的函数,例如迭代器,生成器,都是函数。装饰器,本质就是函数,功能是为其他函数添加新功能。

    二.装饰器遵循的原则(开放封闭原则)

      1.不改变被修饰函数的源代码

      2.不改变被修饰函数的调用方式

    三.实现装饰器的原理构成

      装饰器=高级函数+函数嵌套+闭包

    四.高阶函数

      高级函数的定义:

      1.函数接受的参数是个函数名

      2.函数返回一个函数名

      3.满足以上两个函数既是高阶函数

      我们来看看用高级函数实现装饰器的效果:

    #利用高阶函数无法实现
    import time
    def foo():     #被装饰函数
        time.sleep(0.5)
        print('来自foo')
    
    def test(func):
        start_time=time.time()
        func()
        end_time=time.time()
        print("程序运行时间:%s"%(end_time-start_time))
      return func foo
    =test(foo) foo()

      我们可以发现,虽然高级函数给被修饰函数添加了额外功能,也没修改被装饰函数的调用方式,但是会多执行一次被装饰函数,与原函数实现的功能不符。所以单独使用高级函数,是无法实现装饰器功能。

    五.内嵌函数

      函数嵌套:在函数定义的内部再定义函数,称为函数嵌套。如果只是在函数中再调用其他函数,不是函数嵌套。  

    def  test():
        print('这是个错误的示范')
    
    def test1():
        test()
    非函数嵌套
    def test1():
        def test():
            print('这是内嵌函数')
    函数嵌套

    6.闭包

      闭包:在一个作用域里放入定义变量,相当于打了一个包。

    def bao1(name):
        print('这是闭包一,打包变量name,bao2 ')
        def bao2():
            print('这是闭包二,打包变量bao3')
            def bao3():
                print('这是闭包三,啥都没有打包')

      闭包补充知识:解压序列。

      可以一次性将序列赋值给多个变量。例如:

    l=[1,2,3,4,5,6]        #序列可以是字符串,列表,元组等。
    a,b,c,d,e,f=l          #序列有多少个值,则需要对应数量的变量。
    print(a,b,c,d,e,f)

      解压序列应用:获取第一个及最后一个的值

    l=[1,2,3,4,5,6]
    a,*_,b=l   #*代表中间全部,_为将中间全部抛弃 ,也可以定义为其他变量名
    print(a,b,)
    示例一
    l=[1,2,3,4,5,6]
    a,b,*c,d=l
    print('a',a,'b',b,'c',c,'d',d)
    
    输出结果:
    a 1 b 2 c [3, 4, 5] d 6
    示例二

      

    七.装饰器的实现

      利用高级函数,函数嵌套,实现装饰器。我们可以实现一个基本的装饰器。

    import time
    def test(func):
        def wrag(*args,**kwargs):  #传递被装饰函数的参数
            start_time=time.time()
            res=func(*args,**kwargs)   #返回函数的返回值
            end_time=time.time()
            print("程序运行时间:%s"%(end_time-start_time))
            return res
        return wrag
    
    def foo():
        time.sleep(0.5)
        print('来自foo')
        return 'haha'
    foo=test(foo)   
    foo()

    八.语法糖:@

      语法糖:对于计算器而言,没有任何意义,但是对于人类而言,会显得语法更友好。

      在使用装饰器时,我们需要将被装饰器函数名重新定义,如果有一万个被装饰函数,就需要重复操作该步骤一万次。这明显是不合理的。于是,出现了语法糖: @来帮我进行转换。在被装饰函数定义前,加上@装饰器函数名 即可。

    import time
    def test(func):
        def wrag():
            start_time=time.time()
            res=func()
            end_time=time.time()
            print("程序运行时间:%s"%(end_time-start_time))
            return res
        return wrag
    @test   #foo=test(foo)
    def foo():
        time.sleep(0.5)
        print('来自foo')
        return 'haha'
    
    foo()
    语法糖

    九.有参数装饰器

     如果我们要给装饰器函数传入参数,可以使用闭包,再给装饰器加一个参数。

    import time
    def test1(name):
        def test(func):
            def wrag():
                print(name)
                start_time=time.time()
                res=func()
                end_time=time.time()
                print("程序运行时间:%s"%(end_time-start_time))
                return res
            return wrag
        return test
    @test1('this is test1')   #test1(name)---->test--->foo=test(foo)
    def foo():
        time.sleep(0.5)
        print('来自foo')
        return 'haha'
    
    foo()
    View Code

      

    十.传递函数来进行装饰

    要添加的额外函数有

    def before():
        print 'before'
        
    def after():
        print 'after'

    主体函数:

    def main():
        print 'main'

    装饰器:

    复制代码
    def filter(before_func,after_func):        #要在主体函数前 和 函数后再执行的函数名
        def outer(main_func):                   
            def wrapper():
                 before_result=before_func()   #如果前函数不为None,则执行
                 if(before_result!=None):
                     return before_result
                 main_result=main_func()        #执行主体函数
                 if(main_result!=None):
                     return main_result
                 after_result=after_func()     #如果后函数不为None,则执行
                 if(after_result!=None):
                     return after_result
            return wrapper
        return outer
    复制代码

    执行结果,打印出:

    before
    main
    after

  • 相关阅读:
    15. DML, DDL, LOGON 触发器
    5. 跟踪标记 (Trace Flag) 834, 845 对内存页行为的影响
    4. 跟踪标记 (Trace Flag) 610 对索引组织表(IOT)最小化日志
    14. 类似正则表达式的字符处理问题
    01. SELECT显示和PRINT打印超长的字符
    3. 跟踪标记 (Trace Flag) 1204, 1222 抓取死锁信息
    2. 跟踪标记 (Trace Flag) 3604, 3605 输出DBCC命令结果
    1. 跟踪标记 (Trace Flag) 1117, 1118 文件增长及空间分配方式
    0. 跟踪标记 (Trace Flag) 简介
    SpringBoot + Redis + Shiro 实现权限管理(转)
  • 原文地址:https://www.cnblogs.com/white-small/p/6889855.html
Copyright © 2011-2022 走看看