装饰器。。。。。。
定义:本质是函数,为其他函数添加附加功能
原则: 1.不能修改被装饰的函数的源代码
2.不能修改被装饰函数的调用方式
仔细观察下面代码,看看有什么发现。
内嵌函数+高阶函数+闭包=》装饰器
import time# 内嵌函数def timmer(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) stop_time = time.time() print('run time is %s' % (stop_time - start_time)) return res return wrapper # 返回函数名@timmerdef foo(): time.sleep(3) print('from foo')foo()
高阶函数。。。。。下面的例子中foo就是属于一个高阶函数。
'''高阶函数: 1、函数接收的参数是一个函数名 2、函数的返回值是一个函数名 只要满足其中一个就属于高阶函数'''def fun(): print("from fun")def foo(fun1): fun1()foo(fun)
返回值是函数名的高阶函数
def fun(): print("from fun")def foo(fun1): return fun1foo(fun)()
函数嵌套。。。。。。通过下面的例子,可以看出,函数内可以套函数,而函数也是一个变量,
通过locals()可以看到。
'''函数嵌套'''def fun1(): print("from fun1") def fun2(): print("from fun2") print(locals())fun1()# 运行结果#from fun1#{'fun2':.fun2 at 0x000002A2C4D4AD90>}
闭包闭包,一个函数一个包。。。主要还是作用域,请看
重点来了。装饰器。。。。。。
# 简单的装饰器例子def timer(func): def wrapper(): func() return wrapperdef test(): time.sleep(3) print("test函数执行完毕")res = timer(test)res()
这是不对的,前面说过,装饰器不能修改被装饰函数的源代码,不能修改被装饰函数的调用方式。
这里调用时,修改了调用的方式。。。
那这样呢?
test = timer(test)test()
看着是没有修改调用方式,但是每次调用时都会重新赋值。。。这样不合理
那应该怎么做?下面这样写,仅仅是在函数调用之前加上@装饰器名字即可
@timertest()
看下面的例子,看看都打印了什么。
def timer(func): def wrapper(): func() return wrapper@timerdef test(): time.sleep(2) print("test函数执行完毕") return "test()的返回结果"res = test()print(res)
可以发现,我们并没有得到test()函数的返回值,如果想要得到被装饰函数的返回值,需要这样写
def timer(func): def wrapper(): res = func() return res return wrapper
在装饰器中通过变量来接收被装饰函数的返回值,然后利用return返回。这样一个带有返回值的装饰器就书写完成了。
这些还远远不够,有时候我们被修饰的函数还需要传入一些参数
def timer(func): def wrapper(name, age): res = func(name, age) return res return wrapper@timerdef test(name, age): time.sleep(2) print("name:%s,age:%d," % (name, age)) print("test函数执行完毕") return "test()的返回结果"res = test('june', 18)print(res)
上面的例子虽然可以传递参数,但依然存在不足,当test()的参数变化时,上面的例子就不能用了,需要对装饰器进行改进
def timer(func): def wrapper(*args, **kwargs): res = func(*args, **kwargs) return res return wrapper
上面的这个例子可以实现无论被修饰函数的参数如何让改变,都能够接收。关于*args,**kwargs可以参考
好了,目前为止我们写的装饰器可以传入参数,也可以拥有返回值了,那么如果我们的装饰器还需要参数的话,那。。。。
def auth(filed): print(filed) def fun1(fun): def fun2(*args, **kwargs): fun(*args, **kwargs) return fun2 return fun1@auth("我是装饰器的参数")def foo(): print("from foo")foo()
在原来的基础上再加一层函数。。。
小结,不修改原函数代码,不修改原函数的调用方式。