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

    普通装饰器

    import time
    
    #原始函数
    def add():
        ret=0
        for i in range (3000000):
            ret = ret + i
        print(ret)
    
    
    print("下面开始提需求------------------------------")
    
    #需求: 记录一下执行的时间
    def add():
        start_time=time.time()
        ret=0
        for i in range(3000000):
            ret = ret + i
        print(ret)
        end_time=time.time()
        print("spend %s" % (end_time-start_time))
    add()
    #虽然实现了要求 但是违反了开放封闭原则中的封闭原则
    
    print("修改1---------------------------")
    
    def show_time(func):
        start_time=time.time()
        func()
        end_time=time.time()
        print("spend %s" % (end_time - start_time))
    
    def add():
        ret=0
        for i in range (3000000):
            ret = ret + i
        print(ret)
    
    show_time(add)
    # 没有改变原始函数,但是改变了调用方式.
    # 违反了开放封闭原则中的开放原则
    # 很容易想到可以改成  add()=show_time(add) 就不会改变调用方式
    # 这就需要show_time(add)返回一个函数对象,***
    # 而这个函数对象内则是核心业务函数:执行func() 和 装饰函数时间计算
    # 修改如下:
    
    print("修改2-----------------------")
    
    def show_time(func):
        def inner():
            start_time=time.time()
            func()
            end_time=time.time()
            print("spend %s" % (end_time - start_time))
        return inner
    
    def add():
        ret=0
        for i in range (3000000):
            ret = ret + i
        print(ret)
    
    add=show_time(add)
    add()
    # 函数show_time就是装饰器,它把真正的业务方法func包裹在函数里面,
    # 看起来像add被上下时间函数装饰了。
    # 在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),
    # 这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。
    
    print("修改3-----------------------")
    
    # @符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作,如下示例
    def show_time(func):
        def inner():
            start_time=time.time()
            func()
            end_time=time.time()
            print("spend %s" % (end_time - start_time))
        return inner
    
    @show_time   #add=show_time(add)
    def add():
        ret=0
        for i in range (3000000):
            ret = ret + i
        print(ret)
    
    @show_time
    def bar():
        print("in the bar")
        time.sleep(2)
    
    add()
    bar()
    #如上所示,这样我们就可以省去add = show_time(add)这一句了,直接调用add()即可得到想要的结果。
    #这里需要注意:add=show_time(add)其实是把inner引用的对象引用给了add,
    # 而inner里的变量func之所以可以用,就是因为inner是一个闭包函数。
    #@show_time帮我们做的事情就是当我们执行业务逻辑add()时,
    # 执行的代码由add函数代码块部分转到inner的代码块部分
    
    print("带参数的被装饰函数-----------------------")
    
    def show_time(func):
        def inner(a,b):   #注意要和add()函数中的形参个数对应
            start_time=time.time()
            func(a,b)
            end_time=time.time()
            print("spend %s" % (end_time - start_time))
        return inner
    
    @show_time   #add=show_time(add)
    def add(a,b):
        ret=0
        time.sleep(2)
        print(a+b)
    
    add(2,4)
    
    print("被装饰函数有返回值的情况-----------------------")
    
    def show_time(func):
        def inner(a,b):   #注意要和add()函数中的形参个数对应
            start_time=time.time()
            ret= func(a,b)
            end_time=time.time()
            print("spend %s" % (end_time - start_time))
            return ret  # 若被装饰函数有返回值,则inner函数也一定要返回func(a,b)的结果
    
        return inner
    
    @show_time   #add=show_time(add)
    def add(a,b):
        ret=0
        time.sleep(2)
        print(a+b)
    
    add(2,2)

    装饰器带参数的情况

    import time
    
    flag=False
    def outer(flag):
        def timer(func):
            def inner(*args,**kwargs):
                if flag:
                    print(time.time())
                    ret = func(*args,**kwargs) # 原来的函数
                else:
                    ret = func(*args, **kwargs) # 原来的函数
                return ret
            return inner
        return timer
    
    
    # @timer的时候   func1=timer(func1)  对应的是inner
    @outer(True)   #func1=timer(func1)    inner
    def func1():
        print("func1")
    
    @outer(False)
    def func2():
        print("func2")
    
    func1()
    func2()

    多个装饰器修饰同一个函数

    def wrapper1(func):
        def inner(*args, **kwargs):
            print('wrapper1 前')  # 2
            ret = func(*args, **kwargs)
            print('wrapper1 后')  # 4
            return ret
        return inner
    
    def wrapper2(func):
        def inner(*args, **kwargs):
            print('wrapper2 前')  # 1
            ret = func(*args, **kwargs)
            print('wrapper2 后')  # 5
            return ret
        return inner
    
    @wrapper2  # func1 = wrapper2(func1)  wrapper2.inner   func=wrapper1.inner
    @wrapper1  # func1 = wrapper1(func1)  wrapper1.inner   func=func1
    def func1():
        print('func1')  # 3
        return 'func1的返回值'
    
    print(func1())  # 6

    装饰器的修复技术

    import time
    
    from functools import wraps
    
    def timer(func):
        @wraps(func)
        def inner():
            print(time.time())
            ret = func()  # 原来的函数
            return ret
        return inner
    
    
    @timer  # func1 = timer(func1)
    def func1():
        """
        func1 xxxx
        :return:
        """
        print('func1')
        return 'func1的返回值'
    
    @timer  # func1 = timer(func1)
    def func2():
        """
        func2 xxxx
        :return:
        """
        print('func2')
        return 'func2的返回值'
    
    print(func1.__name__)
    print(func2.__name__)
    print(func2.__doc__)
  • 相关阅读:
    Cocos2dx-背景无限循环播放
    centos 7端口和防火墙
    图片裁剪
    spring-boot图片压缩
    vue cli简介
    spring-boot的配置(实时生效)
    spring-boot打成war包放入tomcat运行
    spring-boot上传图片并访问
    linux链接ssh
    mysql远程访问
  • 原文地址:https://www.cnblogs.com/kenD/p/10066156.html
Copyright © 2011-2022 走看看