博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
6、python 装饰器的使用
阅读量:4111 次
发布时间:2019-05-25

本文共 2009 字,大约阅读时间需要 6 分钟。

装饰器的使用可以很好的拓展函数:例如,有一个在项目中频繁使用的函数:从0到10的8次方中随机挑选n个数,现在要对他进行拓展:(计算该函数的运行时间)

原函数:

def getNumList(n):    seq = list(range(pow(10,8)))    x = random.sample(seq, n)    y = sorted(x)    return yresult = getNumList(1000)

最直观也是最简单的办法,直接在该函数中前后加上时间计时,如下:

def getNumList(n):    # 开始前计时:    start_Time = time.time()    seq = list(range(pow(10,7)))    x = random.sample(seq, n)    y = sorted(x)    # 结束后计时:    end_Time = time.time()    # 打印耗时:    print('Time used:', end_Time - start_Time)    return yresult = getNumList(1000)

Time used: 0.24091100692749023

这样的解决方案无可厚非,但如果是集体开发的大型项目,这样的改动通常是不被允许的,如果大家都为了各自的需求在原函数中添加代码,很可能会造成灾难性的后果。

还有一种解决方案,就是将原函数封装到一个新的函数中,在新函数中对原函数的运行时间进行计算,如下:

def getNumList(n):    seq = list(range(pow(10,8)))    x = random.sample(seq, n)    y = sorted(x)    return ydef getNumListTime(n):    # 开始前计时:    start_Time = time.time()    getNumList(n)    # 结束后计时:    end_Time = time.time()    # 打印耗时:    print('Time used:', end_Time - start_Time)result = getNumListTime(1000)

Time used: 8.337044954299927

这种方案不用修改原函数中的代码,看似可行,实际上存在很多的问题。使用该方案不仅需要为每一个需要功能拓展的函数分别新建一个新函数,而且还要修改所有的调用,如果需要修改的函数有成百上千个,这将是巨大的工作量

python中最佳方案是“装饰器”,方法如下:

def getNumListTime(func):    def wrapper(n):        start_Time = time.time()        func(n)        # 结束后计时:        end_Time = time.time()        # 打印耗时:        print('Time used:', end_Time - start_Time)    return wrapper@getNumListTimedef getNumList(n):    seq = list(range(pow(10,8)))    x = random.sample(seq, n)    y = sorted(x)    return yresult = getNumList(1000)

输出:Time used: 9.983274936676025

方法解释:

定义了一个装饰器函数 getNumListTime(),这个函数有三个特殊之处:一是使用函数对象作为参数;二是使用了内部函数(闭包)wrapper( );三是返回值是一个函数对象。
其实这些并不难理解,python中万物皆为对象,当然可以像其它对象一样作为函数的参数和返回值。用@语法对getNumList( )函数进行装饰,在代码中调用getNumList( )函数时,getNumList( )不会立即执行,而是被当作参数传入装饰器函数getNumListTime( )中,然后在闭包wrapper中完成对getNumList( )的调用。

乍看之下使用装饰器与上面提到的函数封装似乎差别不大,仔细分析就会发现装饰器能显著提高开发效率。

首先只需要在函数定义之前添加@语句就能对所有函数进行功能拓展,大大减少了代码测试、版本更新的工作量;
其次丝毫不会影响对该函数的调用,即使该函数被调用了千万次,也不需要任何的修改;
第三最大限度保持了代码的可读性和扩展性,如果需要为原函数增加新的功能,只需要在函数定义前加上一条@语句。

转载地址:http://zkesi.baihongyu.com/

你可能感兴趣的文章
一篇搞懂Java反射机制
查看>>
一篇彻底搞懂Java注解与枚举类
查看>>
【2021-MOOC-浙江大学-陈越、何钦铭-数据结构】树
查看>>
MySQL主从复制不一致的原因以及解决方法
查看>>
RedisTemplate的key默认序列化器问题
查看>>
序列化与自定义序列化
查看>>
ThreadLocal
查看>>
从Executor接口设计看设计模式之最少知识法则
查看>>
OKhttp之Call接口
查看>>
application/x-www-form-urlencoded、multipart/form-data、text/plain
查看>>
关于Content-Length
查看>>
WebRequest post读取源码
查看>>
使用TcpClient可避免HttpWebRequest的常见错误
查看>>
EntityFramework 学习之一 —— 模型概述与环境搭建 .
查看>>
C# 发HTTP请求
查看>>
初试visual studio2012的新型数据库LocalDB
查看>>
启动 LocalDB 和连接到 LocalDB
查看>>
Palindrome Number --回文整数
查看>>
Reverse Integer--反转整数
查看>>
Container With Most Water --装最多水的容器(重)
查看>>