• Python装饰器使用方法总结(一)


    Python装饰器简单的讲就是在不改变原函数或者类的情况下,对原函数或类的扩展新功能的一种函数,这种函数特殊之处在于它的返回值是个函数,这个函数是内嵌原函数的函数。

    对于一般的函数,要想扩展函数的功能,最直接的方式是修改函数的代码,例如:

    定义一个函数f():

    1 import time 
    2 def f():
    3     print("hello")
    4     time.sleep(1)
    5     print("world")

    为了统计该函数的运行时间可以修改代码为:

    import time 
    def f():
        start_time = time.time()
        print("hello")
        time.sleep(1)
        print("world")
        end_time = time.time()
    
        execution_time = (end_time-start_time)*1000
        print("time is %d ms"%execution_time)

    这样就可以对函数f()实现该功能,但是这样就需要修改函数f()的代码了,若是需要统计很多函数的运行时间的话,那么这个工作量就太大了,当然也可以通过定义新的函数g(),将函数f()以形参传递进去,然后在函数g()内部统计时间,比如:

    def g(f):
        start_time = time.time()
        f()
        end_time = time.time()
        execution_time = (end_time-start_time)*1000
        print("time is %d ms"%execution_time)

    这样也可以给函数f()嵌入了计时功能。但是想要拓展这一千万个函数功能,就是要执行一千万次g()函数,所以这样并不理想!接下来,我们可以试着用装饰器来实现,先看看装饰器最原始的面貌。

    def deco(f):
        def wrapper():
            start_time = time.time()
            f()
            end_time = time.time()
            execution_time = (end_time-start_time)*1000
            print("time is %d ms"%execution_time)
        return wrapper()
    
    @deco 
    def f():
        print('hello')
        time.sleep(1)
        print("world")
    
    f()

       这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数f()就在返回函数wrapper()的内部执行。然后在函数f()前面加上@deco,f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多”的函数了,(不需要重复执行原函数)。 

    扩展1:带有固定参数的装饰器

    import time
    
    def deco(f):
        def wrapper(a,b):
            start_time = time.time()
            f(a,b)
            end_time = time.time()
            execution_time = (end_time - start_time)*1000
            print("time is %d ms" % execution_time)
        return wrapper
    
    @deco
    def f(a,b):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b))
    
    if __name__ == '__main__':
        f(3,4)

    扩展2:无固定参数的装饰器

    import time
    
    def deco(f):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            f(*args, **kwargs)
            end_time = time.time()
            execution_time_ = (end_time - start_time)*1000
            print("time is %d ms" %execution_time)
        return wrapper
    
    
    @deco
    def f(a,b):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b))
    
    @deco
    def f2(a,b,c):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b+c))
    
    
    if __name__ == '__main__':
        f2(3,4,5)
        f(3,4)

    扩展3:使用多个装饰器,装饰一个函数

    import time
    
    def deco01(f):
        def wrapper(*args, **kwargs):
            print("this is deco01")
            start_time = time.time()
            f(*args, **kwargs)
            end_time = time.time()
            execution_time = (end_time - start_time)*1000
            print("time is %d ms" % execution_time)
            print("deco01 end here")
        return wrapper
    
    def deco02(f):
        def wrapper(*args, **kwargs):
            print("this is deco02")
            f(*args, **kwargs)
    
            print("deco02 end here")
        return wrapper
    
    @deco01
    @deco02
    def f(a,b):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b))
    
    
    if __name__ == '__main__':
        f(3,4)

    装饰器调用顺序

    装饰器是可以叠加使用的,那么使用装饰器以后代码是啥顺序呢?

    对于Python中的”@”语法糖,装饰器的调用顺序与使用 @ 语法糖声明的顺序相反。

    在这个例子中,”f(3, 4) = deco01(deco02(f(3, 4)))”。

    参考网址:https://www.cnblogs.com/yuzhanhong/p/9180212.html

  • 相关阅读:
    性能分析
    thymeleaf和spring的整合
    Java中二叉树的建立
    面试题
    (转)structs2的相关配置问题
    ==与equal()的区别
    java的基本类型和其包装类
    Ajax调用返回json数组,对象 (JSONArray.fromObject)
    (转)在JSP中调用JAVA类和使用JavaBean有什么区别?
    用log4j查看详细错误信息
  • 原文地址:https://www.cnblogs.com/kuangsyx/p/11924907.html
Copyright © 2020-2023  润新知