版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
简要
- 装饰器的作用:在不改变代码本身添加功能。
- 装饰器其实就是函数引用传递的过程。(具体参考代码片1理解)
- 装饰器在没调用函数前就已经执行代码并装饰了。(具体参考代码片2理解)
- 参数的传递要谨遵“怎样来就怎样回去”(具体参考代码片3理解)
- 被装饰函数如果有返回值的话就需要return哦(具体参考代码片3理解)
- 如果多个装饰器装饰一个函数,装饰是“由下向上”,代码执行是“由上到下”(具体参考代码片4)
- 如果装饰器自己还要传递参数的话,那么就再套一层“def即可”。(具体参考代码片5理解)
- 类也是可以当作装饰器的(具体参考代码片6理解)
代码1:没有参数没有返回值的装饰器
重点是:test1 = set_func(test1)
def set_func(func):
def call_func():
print("----quanxianyanzheng1-----")
print("-----quanxianyanzheng2----")
func()
return call_func
# @set_func 等价于 test1 = set_func(test1)
def test1():
print("----test1----")
# ret = set_func(test1)
# ret()
test1 = set_func(test1) # 使fun形参指向了最初的test1函数
test1()
代码2:装饰器在调用函数之前就已经装饰上了。
def set_func(func):
print("装饰器在函数调用之前已经装饰了")
def call_func(a_num):
print("----quanxianyanzheng1-----")
print("-----quanxianyanzheng2----")
func(a_num)
return call_func
@set_func # 等价于 test1 = set_func(test1)[此时执行代码并不会跳过]
def test1(num):
print("----test1----%d" % num)
@set_func
def test2(num):
print("----test2----%d" % num)
# test1(100) # 因为装饰器的存在,所以就直接调用test1引用的call_func函数
# test2(200)
代码3:不定长且有返回值的函数的装饰(通用装饰器的写法)
def set_func(func):
def call_func(*args,**kwargs): # def call_func(*args,**kwargs): 参数也可以这样写
print("----quanxianyanzheng1-----")
print("-----quanxianyanzheng2----")
# print(args,kwargs)
# func(args, kwargs) # 不行,相当于传递了2个参数 :1个元组,1个字典
return func(*args,**kwargs) # 拆包,拆成-->100,200,300,mm=100,bb=200
return call_func
@set_func # 等价于 test1 = set_func(test1)[此时执行代码并不会跳过]
def test1(num,num2,*args,**kwargs):
# print(type(num))
print("----test1----%d" % num)
print("----test1----%d" % num2)
print("----test1----", args)
print("----test1----", kwargs)
return "ok"
ret=test1(100,200,300,mm=100,bb=200) # 因为装饰器的存在,所以就直接调用test1引用的call_func函数
print(ret)
# 这里就是通用的装饰器了。
# 如果一个函数没有返回值的话,返回的便是none。
代码4:多个装饰器装饰一个函数
def add_qx(func_01):
print("---开始进行装饰权限1的功能---")
def call_func(*args, **kwargs):
print("---这是权限验证1----")
return func_01(*args, **kwargs)
return call_func
def add_xx(func_02):
print("---开始进行装饰xxx的功能---")
def call_func(*args, **kwargs):
print("---这是xxx的功能----")
return func_02(*args, **kwargs)
return call_func
@add_qx
@add_xx
def test1():
print("------test1------")
test1()
# 装饰器装饰的是函数的引用,当qx发现下方不是函数的引用时,便不会装饰,然后当xx变为函数的引用时,qx才会装饰。
# 执行的时候,便是正常执行了,就像单独只有一个装饰器的时候会先执行装饰器一样,所以也会先执行qx再执行xx。
代码5:装饰器如果自己还要有参数。
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
# 带有参数的装饰器装饰过程分为2步:
# 1. 调用set_level函数,把1当做实参
# 2. set_level返回一个装饰器的引用,即set_func
# 3. 用返回的set_func对test1函数进行装饰(装饰过程与之前一样)
@set_level(1)
def test1():
print("-----test1---")
return "ok"
@set_level(2)
def test2():
print("-----test2---")
return "ok"
test1()
test2()
代码6:用类来当装饰器。
重点是:
1.创建对象会调用__init__方法,而__init__方法负责接收这个参数(函数的引用)。
2.实例对象() 会自动调用__call__方法
class Test(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("这里是装饰器添加的功能.....")
return self.func(*args, **kwargs) # 拆包 拆成---->1, 2, 3,mm=66
@Test # 相当于get_str = Test(get_str),get_str成了一个实例对象。 # 最多会让你用类的静态方法当装饰器(静态方法存在一个闭包这样理解便好了)
def get_str(num,*args, **kwargs):
print(num,args, kwargs)
return "haha"
print(get_str(1, 2, 3, mm=66)) # 实例对象(),便会调用__call__方法
补充
- 如果需要用类中的静态方法作为装饰器的话(谁会这么无聊?好吧,也许实际需求就会那么无聊。),我们简单理解静态方法中有个闭包就可以了。
- 闭包是什么?闭包就是def套def;这不是装饰器吗?是啊,这就是啊!-。-