zoukankan      html  css  js  c++  java
  • @wraps 修饰器:让你的 Python 代码更加简短可爱 | 从简单实例来认识它

    @wraps 修饰器:让你的 Python 代码更加简短可爱 | 从简单实例来认识它

    我们在上一篇文章(Python实例来认识并发与并行)中用到了 @timer ,在函数定义时,加上一个小小的 @timer ,这样,函数执行结束后,就会自动在控制台汇报自己运行的时间。

    比如下面这样:

    @timer
    def piper():
        for i in range(10000):
            i = i * i ** 10
    
    piper()
    
    输出:
    timer: using 0.00600 s
    

    实际上,这个计时器逻辑 @timer 是我们自己用 Python 中的修饰器特性来实现的。

    拆解逻辑

    其实我们不用修饰器,自己也能实现计时的逻辑。

    def piper():
        for i in range(10000):
            i = i * i ** 10
    
    t = time.time()  # 记录函数开始时时间
    piper()
    print(f"timer: using {time.time() - t :.5f} s")  # 获取函数运行时间并打印
    

    注意到我们执行函数时,在其上下都包裹上了逻辑。如果我们希望函数自带计时逻辑,那么为了包住原函数,只能去新定义一个函数。

    def time_wrapper(func):
        # func 是一个函数
        t = time.time()
        func()
        print(f"timer: using {time.time() - t :.5f} s")
    
    time_wrapper(piper)
    
    输出:
    timer: using 0.00600 s
    

    我们想测试某一个函数运行时间时,将函数名输入到 time_wrapper 里面就好。

    更优雅的改进

    上述代码显然有缺点:

    • 我们在编程时,心智负担增大了;此外,代码更冗长了
    • 如果我们只是希望函数新增一个功能,显然用 time_wrapper 是不行的,因为其并没有改变 piper 本身

    于是我们请出今天的主角 修饰器@wraps

    还用我们的 timer 举例子,我们让所有在 @timer 下的函数,都经过如下处理:

    def timer(func):
        @wraps(func)
        def inner_func():
            t = time.time()
            rts = func()
            print(f"timer: using {time.time() - t :.5f} s")
            return rts
        return inner_func
    

    piper 为例,我们经历了如下变化。

    @timer
    def 原始piper():
        for i in range(10000):
            i = i * i ** 10
    

    实际上,当你再调用 piper 时,你的 piper 内部逻辑早已变为:

    def 当前piper():
        t = time.time()
        rts = 原始piper()
        print(f"timer: using {time.time() - t :.5f} s")
        return rts
    

    总结

    本文简单与读者朋友们「科普」一下修饰器,注意到我们这里实际上仅仅修饰了无参数的函数。其实,修饰器还有许多更加优雅用途,比如传入参数 *args, **kwargs ,修饰类 __call__ 等用法。期待以后我遇到好的应用场景,将经验分享给朋友们。

    记得点个『在看』!

    我是小拍,关注我!

  • 相关阅读:
    poj1125传播谣言(弗洛伊德,求最长路)
    poj2253青蛙(可到达路径的单次跳跃最短距离)
    poj1860 兑换货币(bellman ford判断正环)
    poj1062 昂贵的礼物(dijkstra+枚举)
    hdu4081 秦始皇修路(次小生成树)
    梦想,永不停息!
    nofollow标签如何使用
    后台地址报错:Service Unavailable
    DEDECMS批量修改默认文章和列表命名规则的方法
    FreeOnTerminate 的线程在线程管理类的Destroy释放时手工释放的问题
  • 原文地址:https://www.cnblogs.com/piperliu/p/14881399.html
Copyright © 2011-2022 走看看