1、装饰器的特点
我们希望在不修改原函数的情况下,来对函数进行扩展。
2、传统方法:对 add函数 增加日志打印
def add(a , b):
'''
求任意两个数的和
'''
r = a + b
return r
def print_log(func): # print_log 就是 装饰器函数
# 创建一个新函数
def new_function(*args , **kwargs):
print('开始执行~~~~')
result = func(*args , **kwargs)
print('执行结束~~~~')
return result
return new_function
# 此处传 add 引用, 而不是调用 add() 。如果传 add(),是将add函数执行完毕后的结果传进去
r=print_log(add)
print('求和:',r(10 , 30))
运行结果:
开始执行~~~~
执行结束~~~~
求和: 40
3、使用 装饰器 对上面代码优化
def print_log(func): # print_log 就是 装饰器函数
# 创建一个新函数
def new_function(*args , **kwargs):
print('开始执行~~~~')
result = func(*args , **kwargs)
print('执行结束~~~~')
return result
return new_function
@print_log # 装饰器print_log函数 对 add函数 进行扩展
def add(a , b):
'''
求任意两个数的和
'''
r = a + b
return r
r=add(10 , 30)
print('求和:',r)
运行结果与上面是一致的:
开始执行~~~
执行结束~~~
求和: 40
像 print_log()
这种函数我们就称它为 装饰器 。
通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展。
在定义函数时,可以通过 @
装饰器,来使用指定的装饰器,来装饰当前的函数,
可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰。
说明:
*args
表示接收所有的 位置参数;
**kwargs
表示接收所有的 键值参数 。
4、使用多个装饰器
def print_log(func): # print_log 就是 装饰器函数
# 创建一个新函数
def new_function(*args , **kwargs):
print('开始执行~~~~')
result = func(*args , **kwargs)
print('执行结束~~~~')
return result
return new_function
def fn3(func):
# 创建一个新函数
def new_function(*args , **kwargs):
print('fn3装饰~开始执行~~~~')
result = func(*args , **kwargs)
print('fn3装饰~执行结束~~~~')
return result
return new_function
@fn3
@print_log
def add(a , b): # add上有两个装饰器去其进行扩展
'''
求任意两个数的和
'''
r = a + b
return r
r=add(10 , 30)
print('求和:',r)
运行结果:
fn3装饰~开始执行~~~~
开始执行~~~~
执行结束~~~~
fn3装饰~执行结束~~~~
求和: 40
5、带有参数的装饰器
5.1、传统方式
调用不同函数,要有不同的权限验证。
比如 调用test1() 函数时,就要验证 是否有test1的权限;调用test2() 函数时,就要验证 是否有 test2的权限。
# 定义装饰器函数
def set_func(func):
def call_func(*args,**kwargs):
level = args[0]
if level == 1:
print("------- 权限级别1 ,验证------------")
elif level == 2:
print("-------- 权限级别2,验证------------")
return func()
return call_func
## 定义 test1 函数
@set_func
def test1():
print("-------test1----------")
return "ok"
# 定义 test2 函数
@set_func
def test2():
print("-------test2----------")
return "ok"
## 调用函数时,要传入权限级别的值
test1(1)
test2(2)
运行结果:
------- 权限级别1 ,验证------------
-------test1----------
-------- 权限级别2,验证------------
-------test2----------
说明:
对 test1()、test2() 的权限级别 是让 调用者 来设置, 调用者 可以随意设置 权限级别,那就就没有任何的安全可言。所以上面的方式是不可取的。
正确的做是 在函数 定义时 加上相应的权限级别,而 调用者只是调用。
5.2、使用带有参数的装饰器
在 @set_func
装饰器 外层 再增加一层装饰器 set_level
:
# 定义装饰器函数
def set_level(level_num):
def set_func(func):
def call_func(*args,**kwargs):
if level_num == 1:
print("------- 权限级别1 ,验证------------")
elif level_num == 2:
print("-------- 权限级别2,验证------------")
return func()
return call_func
return set_func
# 定义 test1 函数
@set_level(1)
def test1():
print("-------test1----------")
return "ok"
# 定义 test2 函数
@set_level(2)
def test2():
print("-------test2----------")
return "ok"
# 调用
test1()
test2()
运行结果跟上面一致:
------- 权限级别1 ,验证------------
-------test1----------
-------- 权限级别1,验证------------
-------test2----------
6、类装饰器
class Test(object):
def __init__(self,func):
self.func=func
def __call__(self):
print("这里是装饰器添加的功能")
return self.func()
@Test # 相当于 get_str=Test(get_str) ,调用类中的__call__
def get_str():
return "zhangsan"
# 调用
print(get_str())
运行结果:
这里是装饰器添加的功能
zhangsan