zoukankan      html  css  js  c++  java
  • day 11

    装饰器

    装饰器形成的过程:最简单的装饰器——有返回值的——有一个参数——万能参数
    装饰器的作用:不想修改函数的调用方式 但是还想在原来的函数前后添加功能
    原则:开放封闭原则
    语法糖:@装饰器函数名
    装饰器的固定模式

    原则:开放封闭原则
    开放:对扩展是开放的
    封闭:对修改是封闭的

    首先我们来逐步实现这么一个功能吧

    计算代码运行的时间

    #先来看下需要的组件
    import time  #time 模块
    
    time.time()       #获取当前时间
    time.sleep(5)      #让程序睡眠多少时间
    
    print(time.time()) #来试下

    我们来写一个可以计算时间的函数

    def func():
        start=time.time()
        time.sleep(0.1)   #时间太短 系统会显示 0.0,所以我们让他休眠 0.1s
        print("计算程序执行的时间")
        end=time.time()
        print(end-start)
    
    func()

    但是这里有一个问题:如果要计算很多函数的运行时间,那不是要在函数中都加上几行计算的代码,这显然是不可行的,一般写好的没问题的函数,是不会去对它进行修改,而且还很麻烦

    所以这里我们写一个计算时间的函数独立出来

    def times(f):
        start=time.time()
        time.sleep(0.1)
        f()
        end=time.time()
        print(end-start)
    
    
    def func():
        print("计算程序执行的时间")
    
    
    def func2():
        print(time.sleep(5))
    
    times(func)
    times(func2)

    但是这样貌似还有一个问题,我要计算时间的函数都要调用 times() 函数,这样其实是很麻烦的

    最终还是要调用 func() 就可以计算运行时间,就是说你调用的是 func() 其实调用的 times() 这就很完美了

    接着我们来了解下装饰器吧,解决这样的问题

    先来写一个简单的装饰器

    #一个简单的装饰器
    import time
    def func():
        time.sleep(0.1)
        print('你好,世界')
    
    def timmer(f):  #装饰器函数
        def inner():
            start = time.time()
            f()    #被装饰的函数
            end = time.time()
            print(end - start)
        return inner
    
    func = timmer(func)    #通过这一步就可以使用 func 调用 timmer 了
    func()

    我们这里做的事情就是:在不想修改函数的调用方式的情况下  但还想在原来的函数前后添加功能

    接着我们来看另一个甜甜的东西——语法糖

    import time
    
    def timmer(f):  #装饰器函数
        def inner():
            start = time.time()
         time.sleep(0.1)  f()   
    #被装饰的函数 end = time.time() print(end - start) return inner @timmer #语法糖 替代下面 func = timmer(func) 这句话 def func(): time.sleep(0.1) print('你好,世界') #func = timmer(func) #通过这一步就可以使用 func 调用 timmer 了 func()

    然后我们来看接收返回值的装饰器

    import time
    
    def timmer(f):      #装饰器函数
        def inner():
            start=time.time()
            time.sleep(0.1)
            ret = f()         #被装饰的函数
            end=time.time()
            print(end-start)
            return ret  #接收 func() 函数的返回值    
        return inner    #这个地方要穿函数的名字 而不是加括号
    
    @timmer             #语法糖 替代下面 func = timmer(func) 这句话
    def func():
        print('你好,世界')
        return 'Hello'
    
    print(func())       #返回值打印  返回值为:Hello

    最后我们来看带参数的装饰器,一个参数与万能参数是一样的,只是参数的不同罢了

    #一个参数的装饰器
    import time
    
    def timmer(f):      #装饰器函数
        def inner(a):   #3.给 inner() 加上参数
            start=time.time()
            time.sleep(0.1)
            ret = f(a)  #4.由于 inner() 把参数传给了 f(),所以 f() 也要加上参数,最后测试传值
            end=time.time()
            print(end-start)
            return ret  #接收 func() 函数的返回值
        return inner
    
    @timmer             #语法糖 替代下面 func = timmer(func) 这句话
    def func(a):        #2.这里也要加上参数,由于执行 func 时,实际执行的 inner(),所以 inner() 也要加上参数
        print("计算程序执行的时间",a)
        return 'Hello'
    
    print(func("123"))  #1.加入参数
    
    #输出结果
    '''
    计算程序执行的时间 123
    0.10937380790710449
    Hello
    '''
    ###万能参数的装饰器
    #可以看出 只是在 a 的位置更换了 *args **kwargs 来接收参数
    import time
    
    def timmer(f):      
        def inner(*args,**kwargs):   
            start=time.time()
            time.sleep(0.1)
            ret = f(*args,**kwargs)
            end=time.time()
            print(end-start)
            return ret  
        return inner
    
    @timmer             
    def func(*args,**kwargs):        
        print("计算程序执行的时间",args,kwargs)    #2. 就是这个位置的 kwargs,如果写了,打印时会出现一个 ' {} ' 空字典,并不会报错
        return 'Hello'
    
    print(func('1','2','3',k=100))    #1. 不需要关键字传参时,kwargs 可以不写
    
    #输出结果
    '''
    计算程序执行的时间 ('1', '2', '3') {'k': 100}
    0.1093745231628418
    Hello
    '''

    好了,以上就是我们对于装饰器完善的最终结果了

    装饰器的固定模式

    def wrapper(f):     #装饰器函数,f是被装饰的函数
        def inner(*args,**kwargs):    #定义一个内置函数,且和下面统级别的返回值名字一致且不加括号
                                      #动态参数一定要原封不动的传给 被装饰的函数 f()
            '''在被装饰函数之前要做的事'''
            ret = f(*args,**kwargs)   #被装饰的函数  函数执行完的返回值要原封不动传给 return
            '''在被装饰函数之后要做的事'''
            return ret
        return inner
    
    @wrapper         #语法糖 @装饰器函数名 等价于 func = wrapper(func)
    def func(a,b):     #被装饰的函数
        time.sleep(0.01)
        print('你好:世界',a,b)
        return '新年好'
    #print(func(23,45))  #接收返回值
    ret = func(23,45)   #接收返回值
    print(ret)
  • 相关阅读:
    Redis --- 客户端 --- Another Redis Desktop Manager
    Docker --- 记录安装与使用过程中遇到的问题
    Docker安装教程
    Python --- pip --- No module named 'pip'异常问题
    天气接口测试用例生成报告
    jsonpath使用
    python小知识,字典
    python小知识,列表推导式
    python小知识,sort和serted的区别
    如何查看app启动的activity
  • 原文地址:https://www.cnblogs.com/ysging/p/10061904.html
Copyright © 2011-2022 走看看