一、理论
1、装饰器定义
本质上是函数(装饰其他函数),就是为其他函数添加附加功能。
2、原则
1、不能修改被装饰的函数的源代码
2、不能修改被装饰的函数的调用方式
3、实现装饰器知识储备:
1.函数即“变量”
2.高阶函数(a.把一个函数名当做实参传给另外一个函数(不修改被装饰函数源代码的情况下为其添加功能);b.返回值中包含函数名(不修改函数的调用方法))
3.嵌套函数
而高阶函数 + 嵌套函数 = 装饰器
二、实现
先说一下高阶函数,高阶函数的定义上面已经说了(a、把一个函数名当做实参传给另外一个函数;b.返回值中包含函数名)。只要实现了a条件就是高阶函数,b为可选条件。
现在有一个最原始的函数func
def func():
time.sleep(3)
print("in the func")
现在要写一个高阶函数,要把func以一个参数的形式传入这个高阶函数中,并给func函数添加一个计算func函数运行时间的功能
def test1(func):
start_time = time.time()
func()
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time))
此时如果要实现功能的话只需要调用test1就行了,这样的话不符合装饰器的原则。
那如何在调用func的同时也实现想要进行装饰的功能(计算func的运行时间)那。
我们用嵌套函数试试
def foo():
print("in the foo")
def func():
time.sleep(3)
print("in the func")
start_time = time.time()
func()
stop_time = time.time()
print("the run time is %s" % (stop_time - start_time))
此时也是只要调用foo函数就行了。和用高阶函数一样。那我如何在调用func 的同时也能实现附加功能那。此时不防用高阶函数 + 嵌套函数来试试。我先用一个高阶函数来接受func作为参数,然后在高阶函数中嵌套一个函数来添加附加功能。并将嵌套的函数作为返回值传出来。
def test5(func):
def test4():
start_time = time.time()
func()
stop_time = time.time()
print("the run time is %s" % (stop_time - start_time))
return test4
此时如果应该怎样去调用这些函数那,我们需要定义一个变量来接受test4(添加附件功能的函数),然后定义这个函数就可以了。
func = test5(func)
func()
此时的func实际上就是test5中嵌套的test4。运行程序,此时的打印结果为
in the test3
the run time is 3.0007569789886475
基本上实现了装饰器的功能,但是也改变了原函数的调用方法。在python中有一个装饰器的修饰方法。就是在原函数的上一行加上“@装饰器函数”。这样就可以直接调用原函数,而且实现附加功能了。例如上面我们是用test5来作为func的装饰器函数的,此时如果在func的定义函数的上一行加上“@test5”,此时只需要调用func函数也能实现附加功能
@test5
def func():
time.sleep(3)
print("in the func")
现在调用直接调用func函数也能实现附加功能了。而这里的“@test5”的功能就相当于“func = test5(func)”。到此装饰器就实现了。但是如果func函数也是有参数传入的那应该怎么办那。上面说过了其实被装饰器装饰过的函数,在调用时,实际上是调用的装饰器函数中嵌套的函数,那么我们在嵌套函数的定义中也写上参数不就解决了嘛。是的。但是参数的个数是不确定的,如何在不确定参数的情况下,接受全部参数,如下所示
def test5(func):
def test4(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
stop_time = time.time()
print("the run time is %s" % (stop_time - start_time))
return test4
这样装饰器就完全实现了。
现在有两个函数,表示两种不同的登录方式,一个是本地登录,另外一个是需要远程连接服务器认证的。那么如何同时给这两个函数,区别去添加功能,并且将第一个函数的返回值也传出去。首先需要给装饰器传入一个参数来区别两种登录方式。
#第一个登录函数(有返回值)
@auth(auth_type="local")
def login(*args, **kwargs):
print("welcome to home page")
return "from home"
第二个登录函数
@auth(auth_type="ldap")
def loginTwo(*args, **kwargs):
print("welcome to loginTwo page")
此时装饰器1、多嵌套一层来接受auth_type参数,2、如下如所示红框内为返回原函数的返回值。
图1代码下载:https://github.com/zhangyunf/python-.git
网友评论