博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python学习系列:装饰器
阅读量:6229 次
发布时间:2019-06-21

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

如果有好多函数,有天老大需要我们给这些函数添加上某些功能,但是不能修改原函数的代码,也不能改变其运行方式,怎么办?

比如我们有如下两个函数:

import timedef test1():    time.sleep(1) #模拟函数运行时间    print("this is test1 function")def tests2():    time.sleep(1) #模拟函数运行时间    print("this is test2 function")

 

需求:获取到上面两个函数的运行时间,该如何实现?

 第一种方式,就是逐个修改函数,将需要添加的功能代码加上去:

import timedef test1():    start_time = time.time()    time.sleep(1) #模拟函数运行时间    print("this is test1 function")    stop_time = time.time()    print("func run time is %s"%(stop_time-start_time))def test2():    start_time = time.time()    time.sleep(1) #模拟函数运行时间    print("this is test2 function")    stop_time = time.time()    print("func run time is %s"%(stop_time-start_time))test1()test2()

 

运行结果:

上面的方法虽然可以实现,但是非常的笨拙。我们有没有其他的办法,让我们先看看用装饰器是怎么来实现:

 
import timedef timmer(func):    def wrapper(*args,**kwargs):        start_time = time.time()        func()        stop_time = time.time()        print("func run time is %s"%(stop_time-start_time))    return wrapper@timmerdef test1():    time.sleep(1)    print("this is test1 function")@timmerdef test2():    time.sleep(1)    print("this is test2 function")test1()test2()
 

 

运行结果:

通过上面的代码我们看到了通过装饰器是怎么来实现既不修改原函数代码不修改原函数的运行方式来实现了给函数添加功能。

接下来我们来详细探究一下,装饰器是如何来实现的,先看下面这段代码:

import timedef timmer(func):    def wrapper():        start_time = time.time()        func()        stop_time = time.time()        print("func run time is %s"%(stop_time-start_time))    return wrapperdef test1():    time.sleep(1)    print("this is test1 function")def test2():    time.sleep(1)    print("this is test2 function")test1 = timmer(test1) #函数timmer接收test1函数的指向,返回的是wrapper函数指向。那么test1其实此时是指向wrapper函数体的指针test2 = timmer(test2) #函数timmer接收test2函数的指向,返回的是wrapper函数指向。那么test2其实此时是指向wrapper函数体的指针test1() #此时其实执行的是wrapper函数,wrapper函数里面的func指向的是原来的test1函数。test2() #与test1的原理一样。

 

由此我们可以看出@timmer 等价于 test1 = timmer(test1) 现在我们基本上实现了我们自己的装饰器,但是我们遇到一个问题,如果我们的函数需要传入参数,比如我们的test2函数是下面这样的:
 
def test2(name):    time.sleep(1)    print(name)    print("this is test2 function")
 
运行结果:
TypeError: test2() takes exactly 1 argument (0 given) 为什么会出现这样的情况: 这是因为 wrapper函数里面法func()是没有带参数的,我们通过test2 = timmer(test2),将test2存储的函数体房间号转给了func存储。 但是func是没有带参数的,所以会报上面的错误:需要一个参数,但是一个也没给。我们怎么解决呢? test1 = timmer(test1) 其实test1已经指向了wrapper函数,此时只需要将参数传给wrapper。代码如下:
import timedef timmer(func):    def wrapper(*args,**kwargs):        start_time = time.time()        func(*args,**kwargs)        stop_time = time.time()        print("func run time is %s"%(stop_time-start_time))    return wrapperdef test2():    print("test2 is running")def test1(name):    print(name)    print("test1 is running")test1 = timmer(test1)test2 = timmer(test2)test1("book")test2()
 

运行结果:

"D:\Program Files\Anaconda3\python.exe" C:/Users/mis.WISDOM/PycharmProjects/erpgg/venv/week4/装饰器.pybooktest1 is runningfunc run time is 0.0test2 is runningfunc run time is 0.0Process finished with exit code 0
顺便补一下返回值:
import timedef timmer(func):    def wrapper(*args,**kwargs):        start_time = time.time()        res = func(*args,**kwargs)  #将返回值用res接收到        stop_time = time.time()        print("func run time is %s"%(stop_time-start_time))        return res #将res返回    return wrapper#timmer #等价于test2 =  timmer(test2)def test2():    print("test2 is running") @timmer #等价于test1 = timmer(test1)def test1(name):    print(name)    print("test1 is running")    return "good"
t1 = test1("book") #t1接收test1的返回值。 t2 = test2() #t2接受到test2的返回值 print(t1,t2)
装饰器的终极升级(函数的双层嵌套): 需求说明:home页面需要用用户名密码进行认证,bbs页面需要用ldap服务进行认证,index页面不需要认证。
 
user,passwd = 'root','123456'def auth(type):    def out_wrapper(func):        def wrapper(*args,**kwargs):            if(type=='user'):                username = input("please input username")                password = input("please input password")                if username == user and password == passwd:                    res = func(*args,**kwargs)                    return res                else:                    print("Invalid username or password!!")            elif(type=='ldap'):                print("Ldap认证功能正在开发中")        return wrapper    return out_wrapperdef index():    print("welcome to index !")@auth('user')def home():    print("welcome to home!")@auth('ldap')def bbs():    print("welcome to bbs!")index()home()bbs()
 

运行结果:

"D:\Program Files\Anaconda3\python.exe" C:/Users/mis.WISDOM/PycharmProjects/erpgg/venv/week4/装饰器.pywelcome to index !please input usernamerootplease input password123456welcome to home!Ldap认证功能正在开发中Process finished with exit code 0

 

 

转载于:https://www.cnblogs.com/pyghost/p/10146246.html

你可能感兴趣的文章
数据中心的重要服务器如何保护?
查看>>
Linux 用户的 3 个命令行小技巧
查看>>
yii上传图片、yii上传文件、yii控件activeFileField使用
查看>>
8)基础网络编程和内容回顾
查看>>
Promise 入门(推荐)
查看>>
java jdbc使用配置文件连接数据库
查看>>
ASP.NET MVC中三方登录: 微软、谷歌、Office365
查看>>
迭代器模式
查看>>
Liferay 启动过程分析7-初始化布局模板
查看>>
java格式化json字符串输入到文本中
查看>>
redis主从集群搭建及容灾部署(哨兵sentinel)
查看>>
apollo生产环境配置-实践笔记(附搭建框架图)
查看>>
正则去掉首尾空格以及首尾的
查看>>
CVPR
查看>>
python+selenium自动化测试(四)
查看>>
06Action中的Struts广告
查看>>
BashShell脚本的输入
查看>>
Docker镜像加速器
查看>>
我理解的Java并发基础(一):一些基本概念
查看>>
PHP 策略模式
查看>>