zoukankan      html  css  js  c++  java
  • python语法基础-函数-装饰器-长期维护

    #########################################################

    # 装饰器
    # 装饰器非常重要,面试Python的公司必问,
    # 原则:开放封闭原则
    
    # 开放封闭原则,适用于对已经固定的额功能,和源码,这个原则是为了程序的稳定性,
    # 开放就是对已经有的功能的拓展是开放的,
    # 封闭就是对已经有的功能是不改动的,

    ###############    装饰器的初成和开放封闭原则    ##############

    # 需求:计算程序执行的时间,

    # 第一版:直接在函数的前后增加代码,

    # 需求:计算程序执行的时间,
    # 第一版:直接在函数的前后增加代码,
    import time
    def func():
        start = time.time()  # 这是获取当前的时间戳,#计算时间差使用
        time.sleep(1.01)
        print(123)
        end = time.time()
        print(end - start)  # 1.0140016078948975,这个时间差就是秒了,
    func()
    
    # 这种写法有明显的缺点,
    # 1,这种不符合开放封闭原则
    # 2,这种写法如果有100个函数,你都要加一遍这是不行的,太麻烦了,

    # 第二版:写一个函数,然后把需要计算执行时间的函数作为参数传递进去,

    # 第二版:写一个函数,然后把需要计算执行时间的函数作为参数传递进去,
    def func():
        time.sleep(0.01)
        print(123)
    def timer(f):
        start = time.time()
        f()
        end = time.time()
        print(end - start)
    timer(func)  # 专门写了一个函数用来计算函数的执行时间,
    

    # 第三版:闭包的写法

    # 第三版:闭包的写法
    def func():
        time.sleep(0.01)
        print(123)
    def timer(f):  # 函数作为参数传递进去,就是外部函数的一个变量了,
        def inner():
            start = time.time()
            f()  # 这是内部函数引用外部函数的变量,构成一个闭包,
            end = time.time()
            print(end - start)
        return inner
    # 这就是一个闭包,因为是函数的嵌套,并且函数内部调用函数外部的参数, # 不修改函数的调用方式,还想要在函数的前后添加功能, # timer就是一个装饰器,对函数有装饰作用, func = timer(func) # inner func() # inner() # 所以使用装饰器是一个非常不错的方式在不改变程序内部的情况下,在程序的前后添加功能,

    ###############    最终的装饰器版本    ##############

    # 最终的装饰器版本
    # 解决两个问题,
    # 1是被装饰函数有返回值
    # 2是被装饰函数有参数
    
    import time
    def timer(f):
        def inner(*args, **kwargs):  # 这个参数就是为了能接收被装饰器函数的参数,
            # 为什么要把参数写到内层函数里面,就是因为,被装饰过的函数已经拿到了inner这个函数名了,下一步调用的是inner
            # 所以要给inner传递参数,
            start = time.time()
            ret = f(*args, **kwargs)
            end = time.time()
            print(end - start)
            return ret  # 这个地方要返回是因为被装饰函数可能会有返回值,
            # 这个返回值就是被装饰函数的返回值
        return inner
    
    
    @timer  # func = timer(func)  # inner
    def func(a):
        """函数"""
        time.sleep(0.01)
        print(123)
        print(a)
        return 123
    # func = timer(func)  # inner
    ret = func(1)  # inner(),这个地方已经是调用的inner了,所以一定要在inner中把被装饰函数的返回值返回回来,
    print(func.__name__)  # 这个被装饰器装饰了之后会有问题,inner返回的是inner,而不是func
    print(func.__doc__)  # 这是none
    # print(ret)

    装饰器的固定模式:

    # 所有有一个装饰器的固定模式
    from functools import wraps
    def outer(func):  # 或者叫做wrapper,这就是装饰器的意思,一般会起一个和业务相关的名字,
        @wraps(func)  # 加上这一句,再去打印函数的name的时候,就不会是inner了,
        def inner(*args, **kwargs):  # 一般就是一个inner
            # 在被装饰函数之前写的东西
            ret = func(*args, **kwargs)
            # 在被装饰函数之后写的东西
            return ret
        return inner
    
    @outer  # 这一句就是test=outer(test)
    def test():
        """
        函数测试,
        :return:
        """
        print(123)
    
    test()  # 这个地方就是inner()了,就是
    print(test.__name__)  # 这个被装饰器装饰了之后会有问题,inner返回的是inner,而不是test,@wraps(func)就是解决这个问题,
    print(test.__doc__)

    注意点:

    1,嵌套函数
    2,内部引用外部变量
    3,返回内部函数的名字
    4,被装饰函数的参数
    5,被装饰函数的返回值,
    6,改变inner的名字,

    ###############    装饰器进阶--带参数的装饰器    ##############

    """
    
    装饰器进阶
    1,带参数的装饰器
    
    场景:就是我写了一个计算代码执行时间的装饰器,然后给每一个函数加上了装饰器,
    如果我想要去掉装饰器的时候,就需要一个一个的去掉了,我想要用的时候还需要再一个一个的加上,很麻烦,有什么好的办法?
    
    解决方法:就是给装饰器加上一个参数,然后通过控制参数来判断是否开启装饰器,
    参数就叫做flag,
    这种代码实现就是使用三层装饰器,这样只需要控制flag就可以控制装饰器是否开启了,
    
    
    """
    
    import time
    
    flag = False
    def timmer_out(flag):
        def timmer(func):
            def inner(*args,**kwargs):
                if flag:
                    start = time.time()
                    ret = func(*args,**kwargs)
                    end = time.time()
                    print(end-start)
                    return ret
                else:
                    ret = func(*args, **kwargs)
                    return ret
            return inner
        return timmer
    
    @timmer_out(flag)
    def test1():
        time.sleep(1)
        print(123)
    
    @timmer_out(flag)
    def test2():
        time.sleep(1)
        print(123)
    
    # @timmer:这一句还好理解就是func=timmer(func)
    # @timmer_out(flag):为了传递参数,我们可以再次在装饰器外部加一层,用来传递参数,
    # 这一句要分开看了,第一步是timmer_out(flag),然后返回了timmer,第二步才是@timmer,执行装饰器,
    
    test1()
    test2()

    ###############   装饰器进阶---多个装饰器装饰一个函数    ##############

    """
    装饰器进阶:
    2,多个装饰器装饰一个函数,
    """
    def wrapper1(func):
        def inner():
            print('wrapper1 ,before func')
            func()
            print('wrapper1 ,after func')
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2 ,before func')
            func()
            print('wrapper2 ,after func')
        return inner
    
    @wrapper2
    @wrapper1
    def f():
        print('in f')
    
    f()
    """
    执行结果:
    wrapper2 ,before func
    wrapper1 ,before func
    in f
    wrapper1 ,after func
    wrapper2 ,after func
    说明了几个问题:
    1,多个装饰器是把函数之前的装饰代码都执行之后,然后才是执行被装饰函数,最后是函数之后的装饰代码
    2,函数之前的执行顺序是谁在上面执行谁,这是从上到下,函数之后的执行顺序是谁在下面执行谁,这是从下往上,
    就像是俄罗斯套娃,进的时候从外往里,出的时候从里往外,
    """

    ###############################################

    ############################################

  • 相关阅读:
    IntelliJ IDEA配置Tomcat 与安装Tomcat失败原因
    IntelliJ IDEA创建JavaWeb工程及配置Tomcat部署
    IntelliJ IDEA 通过GsonFormat插件将JSONObject格式的String 解析成实体
    as 插件GsonFormat用法(json字符串快速生成javabean)
    AndroidStudio导入项目一直卡在Building gradle project info最快速解决方案
    arraylist和linkedlist
    BNUOJ 3958 MAX Average Problem
    ZOJ 5579 Stean
    HDU 3401 Trade
    HDU 1695 GCD
  • 原文地址:https://www.cnblogs.com/andy0816/p/12289724.html
Copyright © 2011-2022 走看看