python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数
- (1).只要有被类装饰器装饰的对象,类装饰器的 init 函数就会执行(不需要调用)
- (2).被类装饰器装饰的函数不论被调用几次,init 函数只会执行一次,并且它的执行是被装饰函数声明装饰时就自动执行,不需要手动调用
- (3).当被装饰函数存在参数时,从
__call__
函数传进参数(不必须 *args,但这是一种规范def __call__(self,*args,**kwargs)
) *args是指元组,**kwargs是指字典,可以接受任何形式的参数
注意:
-
(1).类装饰器有类装饰器的参数,函数(被装饰器修饰的函数)有函数的参数,不可混淆
-
(2).类装饰器的参数从
__init__
函数中传,函数的参数从__call__
函数中传
1、不带参数的类装饰器
from datetime import datetime
import time
# 不带参数的类装饰器
class MyLog():
def __init__(self, func):
print("初始化 {}".format(datetime.now()))
time.sleep(1)
self.func = func
def __call__(self, *args, **kwargs):
print("装饰函数 {}".format(datetime.now()))
time.sleep(1)
return self.func(*args, **kwargs)
@MyLog
def show(name):
print("show function start {}".format(datetime.now()))
print(name)
time.sleep(1)
return "success"
if __name__ == '__main__':
result = show("tom")
print(result)
# output
'''
初始化 2019-06-12 23:33:25.696782
装饰函数 2019-06-12 23:33:26.704644
show function start 2019-06-12 23:33:27.705616
tom
success
'''
2、带参数的类装饰器
from datetime import datetime
import time
# 带参数的类装饰器
class MyLog():
def __init__(self, name, age):
print("初始化 {}".format(datetime.now()))
self.name = name
self.age = age
time.sleep(1)
print("类装饰器初始化内容 {}: {} {}".format(self.name, self.age, datetime.now()))
time.sleep(1)
def __call__(self, func):
print("进入装饰函数 {}".format(datetime.now()))
time.sleep(1)
def wrapper(*args, **kwargs):
print("开始装饰函数 {}".format(datetime.now()))
time.sleep(1)
return func(*args, **kwargs)
return wrapper
@MyLog("jack", 22)
def show(name, age):
print("show function start {}".format(datetime.now()))
print("{} : {} {}".format(name, age, datetime.now()))
time.sleep(1)
return "success"
if __name__ == '__main__':
result = show("rose", 20)
print(result)
# output
'''
初始化 2019-06-12 23:35:24.826855
类装饰器初始化内容 jack: 22 2019-06-12 23:35:25.827581
进入装饰函数 2019-06-12 23:35:26.827861
开始装饰函数 2019-06-12 23:35:27.828399
show function start 2019-06-12 23:35:28.828962
rose : 20 2019-06-12 23:35:28.828962
success
'''
3、处理被装饰函数的参数
from datetime import datetime
import time
from functools import wraps
# 带参数的类装饰器
class MyLog():
def __init__(self, name, age):
print("初始化 {}".format(datetime.now()))
self.name = name
self.age = age
time.sleep(1)
print("类装饰器初始化内容 {}: {} {}".format(self.name, self.age, datetime.now()))
time.sleep(1)
def __call__(self, func):
print("进入装饰函数 {}".format(datetime.now()))
time.sleep(1)
@wraps(func)
def wrapper(*args, **kwargs):
print("开始装饰函数 {}".format(datetime.now()))
# 需要先将参数元组形式转换成列表,进行操作
old_args = list(args)
new_args = []
# kwargs 参数是字典的形式,直接可以键值对复制修改
for index, var in enumerate(old_args):
if var == "rose":
var = "mary"
new_args.append(var)
time.sleep(1)
return func(*tuple(new_args), **kwargs)
return wrapper
@MyLog("jack", 22)
def show(name, age):
print("show function start {}".format(datetime.now()))
print("{} : {} {}".format(name, age, datetime.now()))
time.sleep(1)
return "success"
if __name__ == '__main__':
result = show("rose", 20)
print(result)
# output
# 我们可以看到原函数传参名字 rose 被修改成了mary
# 年龄的参数我们并没有修改,不会影响到年龄参数
'''
初始化 2019-06-12 23:47:32.545398
类装饰器初始化内容 jack: 22 2019-06-12 23:47:33.545863
进入装饰函数 2019-06-12 23:47:34.546187
开始装饰函数 2019-06-12 23:47:35.546515
show function start 2019-06-12 23:47:36.546834
mary : 20 2019-06-12 23:47:36.546834
success
'''