zoukankan      html  css  js  c++  java
  • Python装饰器举例分析

    概述

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

    我们要需要一个能测试函数运行时间的decorator,可以定义如下:

    def timer(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            end_time = time.time()
            print("Run time is: %s" % (end_time - start_time))
            return res
        return wrapper
    

    因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

    @timer
    def fun():
        time.sleep(1)
        print("This is a test")
        return "OK"
    

    运行结果就是:

    This is a test
    Run time is: 1.0000572204589844
    OK
    

    把@timer放在fun()处就相当于执行了语句:

    fun = timer(fun)
    

    如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,比如加上名字:

    def timer(name):
        def decorator(func):
            def wrapper(*args, **kwargs):
                start_time = time.time()
                res = func(*args, **kwargs)
                end_time = time.time()
                print("Name is: %s ; Run time is: %s" % (name, (end_time - start_time)))
                return res
            return wrapper
        return decorator
    

    调用及结果显示如下:

    @timer("Lance#")
    def fun():
        time.sleep(1)
        print("This is a test")
        return "OK"
    
    This is a test
    Name is: Lance# ; Run time is: 1.0000572204589844
    OK
    

    和两层嵌套的decorator相比,三层嵌套的效果是这样的:

    fun = timer("Lance#")(fun)
    

    因为函数也是对象,它也有__name__等属性。
    在未加装饰器之前的fun()函数,调用 fun的__name__属性结果是 'fun',但经过decorator装饰之后的函数,它们的__name__已经从原来的'fun'变成了'wrapper'

    所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    Python内置的functools.wraps就可以完成这个任务,所以,一个完整的decorator的写法如下:

    import functools
    
    def timer(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            end_time = time.time()
            print("Run time is: %s" % (end_time - start_time))
            return res
        return wrapper
    

    整体代码如下:

    __Author__ = "Lance#"
    
    # -*- coding = utf-8 -*-
    
    import time
    import functools
    
    def timer(name):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                start_time = time.time()
                res = func(*args, **kwargs)
                end_time = time.time()
                print("Name is: %s ; Run time is: %s" % (name, (end_time - start_time)))
                return res
            return wrapper
        return decorator
    
    @timer("Lance#")
    def fun():
        time.sleep(1)
        print("This is a test")
        return "OK"
    
    if __name__ == '__main__':
        print(fun())
    
  • 相关阅读:
    SkylineGlobe 7.0.1 & 7.0.2版本Web开发 如何实现对三维模型和地形的剖切展示
    SkylineGlobe 7.0.1 & 7.0.2版本Web开发 如何正确使用三维地图控件和工程树控件
    SkylineGlobe TerraExplorer for Web 7.1.0版本 接口示例
    如何解决一个从SkylineGlobe5版本升级到7版本遇到的小问题
    Cesium如何通过addImageryProvider方法加载SkylineGlobe Server发布的WMS服务
    SkylineGlobe7.0.1版本 支持SQLite(*.sqlite;*.db)数据库
    SkylineGlobe7.0.1版本 通过鼠标左右平移模型对象
    显示器文字发虚的一种原因
    HttpClient + IIS压缩动态内容
    C# Async Await 注意事项
  • 原文地址:https://www.cnblogs.com/GyForever1004/p/8372228.html
Copyright © 2011-2022 走看看