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

    直接进入主题

    原代码

    以下是原代码,要求给改代码添加统计时间功能

    import time
    
    def say_hello():
        time.sleep(1)
        print("Hi!")
    
    say_hello()

    版本1(直接在原函数上修改)

    可能有的同学就做出了下面这个版本

    import time
    
    def say_hello():
        start_time=time.time()
        time.sleep(1)
        print("Hi!")
        stop_time=time.time()
        print('该函数运行时间为:%s' %(stop_time-start_time))
    
    say_hello()
    #输出:
    # Hi!
    # 该函数运行时间为:1.0008747577667236

      该版本存在的问题

    1. 直接修改了函数的原始内容
    2. 当如果有第二个函数需要实现相同的功能是,需要重新做一遍重复的工作

    版本2(将函数当做参数传入)

      经过修改上面的版本我们做出了新的代码

    import time
    
    def run_time(func):
        start_time=time.time()
        func()
        stop_time=time.time()
        print('该函数运行时间为:%s' %(stop_time-start_time))
    
    def say_hello():
        time.sleep(1)
        print("Hi!")
    
    run_time(say_hello)

      该版本通过定义一个新的函数 run_time ,然后再新函数中调用原来的函数,实现计算函数的运行时间功能

      但是该版本有个问题就是修改了原函数的调用方式,这样很不好。

    版本3(修改原函数的内容)

    import time
    
    def run_time(func):
        def wrapper():
            start_time=time.time()
            func()
            stop_time=time.time()
            print('该函数运行时间为:%s' %(stop_time-start_time))
        return  wrapper
    
    
    def say_hello():
        time.sleep(1)
        print("Hi!")
    
    say_hello=run_time(say_hello)
    
    say_hello()

      于是乎我们就有了以上的新代码,该代码即没有修改原函数,也没有修改函数的调用方式。

      巧妙的通过返回函数 wrapper ,在 执行say_hello=run_time(say_hello)  这句代码将 say_hello 的内容修改。

      这基本上算是Python中装饰器的基本架子了。

      再把  say_hello=run_time(say_hello)  这句代码优化下就变为下面的版本了。

    版本4(关键词@)

    import time
    
    def run_time(func):
        def wrapper():
            start_time=time.time()
            func()
            stop_time=time.time()
            print('该函数运行时间为:%s' %(stop_time-start_time))
        return  wrapper
    
    @run_time #  这句代码等同于  say_hello=run_time(say_hello)
    def say_hello():
        time.sleep(1)
        print("Hi!")
    
    say_hello()

      这个版本的代码算是一个装饰器了,但是我们又有了一个问题,上面的原函数是没有参数,没有返回值的,如果有参数有返回值又该怎么解决呢?请看下一个版本代码

    版本5(原函数带有参数、返回值时的实现)

      这个版本通过修改 wrapper 函数的参数,并将参数传入 run_time 中传入的 func 函数中,实现了带有参数的调用。

      并给wrapper 函数添加 func 函数执行后的返回值。完美实现了需求。

    import time
    
    def run_time(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            stop_time = time.time()
            print('该函数运行时间为:%s' % (stop_time - start_time))
            return res
        return wrapper
    
    @run_time  # 这句代码等同于  say_hello=run_time(say_hello)
    def say_hello(name):
        time.sleep(1)
        print(name, ":Hi!")
        return "我是返回值"
    
    print(say_hello("Oliver"))
    
    # Oliver :Hi!
    # 该函数运行时间为:1.000196933746338
    # 我是返回值

      现在问题又来了,如果某些函数需要直接输出运行时间,而某些函数需要将运行时间写入文件又该怎么处理呢?

    版本6(装饰器函数需要参数时实现)

      当然有的同学可能会说就写两个装饰器函数呗,但是因为装饰器函数实现的功能基本一致,而如果能想办法给装饰器函数添加一个参数就完美解决这个问题了。请看以下代码

    import time
    
    def run_time(type):
        def deco(func):
            def wrapper(*args, **kwargs):
                start_time = time.time()
                res = func(*args, **kwargs)
                stop_time = time.time()
                content = '该函数运行时间为:%s' % (stop_time - start_time)
                if type == "print":
                    print(content)
                elif type == "write_file":
                    with open("运行时间记录", "a+", encoding='utf8') as f:
                        f.write(
                            '{0} {1}:{2}
    '.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), func.__name__,
                                                     content))
                return res
    
            return wrapper
    
        return deco
    
    
    @run_time("print")  #这段代码相当于 say_hello= run_time("print")(say_hello) ---》也就是  say_hello= deco(say_hello)
    def say_hello(name):
        time.sleep(1)
        print(name, ":Hi!")
        return "我是返回值"
    
    
    @run_time("write_file")
    def say_hello2(name):
        time.sleep(1)
        print(name, ":你好!")
        return "我是say_hello2返回值"
    
    
    print(say_hello("Oliver"))
    print(say_hello2("张三"))
    # 输出:
    # Oliver :Hi!
    # 该函数运行时间为:1.0008816719055176
    # 我是返回值
    # 张三 :你好!
    # 我是say_hello2返回值
    
    # 文件内容:
    # 2018-08-03 10:54:37 say_hello2:该函数运行时间为:1.0004534721374512

    版本7(一个函数多个装饰器)

      当然一个函数也是可以添加多个装饰器的。比如添加验证功能,并且计算函数运行时间。执行的顺序也是从下往上执行的

    如下代码:

    import time
    
    def verify(func):
        def wrapper(*args, **kwargs):
            print("验证一些信息···")
            res = func(*args, **kwargs)
            return res
        return wrapper
    
    def run_time(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            stop_time = time.time()
            print('该函数运行时间为:%s' % (stop_time - start_time))
            return res
        return wrapper
    
    @verify
    @run_time
    def say_hello(name):
        time.sleep(1)
        print(name ,":Hi!")
    
    say_hello('Oliver')
    
    #输出:
    # 验证一些信息···
    # Oliver :Hi!
    # 该函数运行时间为:1.0001380443572998

     

  • 相关阅读:
    零零碎碎
    MFC入门--显示静态图片及调用本地软件
    Python版本OpenCV安装配置及简单实例
    用星星画菱形--Java
    pycharm IDE在导入自定义模块时提示有错,但实际没错
    Cmd使用方式--命令行运行程序
    cv2 & PIL(pillow)显示图像
    C++命令行多文件编译(g++)
    MNIST多图显示--Python练习
    visual studio 2017--括号自动补全
  • 原文地址:https://www.cnblogs.com/haowuji/p/9412968.html
Copyright © 2011-2022 走看看