python装饰器的作用 使得函数包装和方法包装变得更容易阅读和理解
1.一般语法和可能的实现
- 作为一个函数
- 作为一个类
- 参数化装饰器
- 保存内省的装饰器
2.用法和有用的例子
- 参数检查
- 缓存
- 代理
- 上下文提供者
Python 函数不同于其他编程语言,它可以作为第一类对象使用,这是关键。因为装饰器本质上还是函数
很多人对装饰器难以理解,原因是由于以下三点内容没有搞清楚:
关于函数“变量”(或“变量”函数)的理解
关于高阶函数的理解
关于嵌套函数的理解
那么如果能对以上的问题一一攻破,同时遵循装饰器的基本原则,相信会对装饰器有个很好的理解的。那么我们先来看以下装饰器的目的及其原则。
1、装饰器
装饰器实际上就是为了给某程序增添功能,但该程序已经上线或已经被使用,那么就不能大批量的修改源代码,这样是不科学的也是不现实的,因为就产生了装饰器,使得其满足:
- 不能修改被装饰的函数的源代码
- 不能修改被装饰的函数的调用方式
- 满足1、2的情况下给程序增添功能
那么根据需求,同时满足了这三点原则,这才是我们的目的。因为,下面我们从解决这三点原则入手来理解装饰器。
等等,我要在需求之前先说装饰器的原则组成:
< 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器 >
这个式子是贯穿装饰器的灵魂所在!
2、需求实现
improt time
def test():
time.sleep(2)
print("test is running!")
test()
给程序添加统计运行时间(2 second)功能
如何进行呢?
很显然,函数和变量是一样的,都是“一个名字对应内存地址中的一些内容”
那么根据这样的原则,我们就可以理解两个事情:
test1表示的是函数的内存地址
test1()就是调用对在test1这个地址的内容,即函数
如果这两个问题可以理解,那么我们就可以进入到下一个原因(关于高阶函数的理解)
那么对于高阶函数的形式可以有两种:
把一个函数名当作实参传给另外一个函数(“实参高阶函数”)
返回值中包含函数名(“返回值高阶函数”)
那么这里面所说的函数名,实际上就是函数的地址,也可以认为是函数的一个标签而已,并不是调用,是个名词。如果可以把函数名当做实参,那么也就是说可以把函数传递到另一个函数,然后在另一个函数里面做一些操作,根据这些分析来看,这岂不是满足了装饰器三原则中的第一条,即不修改源代码而增加功能。那我们看来一下具体的做法:
还是针对上面那段代码:
improt time
def test():
time.sleep(2)
print("test is running!")
def deco(func):
start = time.time()
func() #2
stop = time.time()
print(stop-start)
deco(test) #1
装饰有参数的函数
improt time
def timer(func)
def deco(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print(stop-start)
return res
return deco
@timer
def test(parameter): #8
time.sleep(2)
print("test is running!")
return "Returned value"
test()
带参数的装饰器
import time
def timer(parameter):
def outer_wrapper(func):
def wrapper(*args, **kwargs):
if parameter == 'task1':
start = time.time()
func(*args, **kwargs)
stop = time.time()
print("the task1 run time is :", stop - start)
elif parameter == 'task2':
start = time.time()
func(*args, **kwargs)
stop = time.time()
print("the task2 run time is :", stop - start)
return wrapper
return outer_wrapper
@timer(parameter='task1')
def task1():
time.sleep(2)
print("in the task1")
@timer(parameter='task2')
def task2():
time.sleep(2)
print("in the task2")
task1()
task2()