关于装饰器的执行过程
来一段简单的装饰器代码:
def zsq(func): def inner(): print("#" * 10) func() return inner @zsq def print_c(): print("c") print_c()
装饰器执行过程:首先系统为两个函数zsq和print_c开辟两个存储空间,在@zsq处执行zsq函数,这里相当于语句print_c=zsq(print_c),于是func指向print_c的空间;然后再在zsq中为函数inner开辟一个空间,其中的内容是print("#" * 10);func(),并将inner函数整体返回给print_c,可知print_c指向inner函数空间;最后调用print_c(),这时执行inner函数的内容。
关于装饰器叠加
(1)装饰器叠加的规则是:从上往下装饰,从下往上执行
(2)语法糖@zsq会对紧跟在其后的函数整体进行装饰,如果其下方紧跟另一个装饰器语法糖,则先执行下面的装饰,然后再对装饰好的函数进行第二次装饰
(3)代码如下:
def zsq(func): def inner(): print("-" * 30) func() return inner def zsq1(func): def inner(): print("*" * 30) func() return inner @zsq @zsq1 def print_cont(): print("666") print_cont()
关于带参数函数的装饰
(1)被装饰函数带参数时,由装饰器的执行过程可知,需要对装饰器进行修改。但需要注意的是,函数带参个数不能确定,要使得装饰器通用,则要使用不定长参数来传参
(2)带参函数通用装饰器代码如下(注意其中不定长参数的装包和拆包,以及函数传参个数):
def zsq(func): def inner(*args, **kwargs): print("*" * 30) # print(args, kwargs) func(*args, **kwargs) return inner @zsq def print_cont(num, num1, num2): print(num, num1, num2) @zsq def print_cont1(num): print(num) print_cont(9, 10, num2=18) print_cont1(10)
关于有返回值函数的装饰
(1)由装饰器执行过程可知,装饰器中的内部函数inner的格式一定要和被装饰函数保持一致,否则装饰出错;这里我们遵循的原则就是:始终保持函数与闭包格式相同
(2)有返回值函数通用装饰器代码如下:
def zsq(func): def inner(*args, **kwargs): print("*" * 30) res = func(*args, **kwargs) return res return inner @zsq def print_cont(num, num1): return num + num1 @zsq def print_cont1(num3): print(num3) print(print_cont(9, 10)) print(print_cont1(20))
关于带参数的装饰器
(1)前面提到的装饰器叠加,如果几个装饰器的格式和内容几乎相同,只是其中的某个参数发生改变,这时我们就想到利用函数传参的方式对代码进一步简化。但是需要注意的是,装饰器格式是固定的,只能传入要装饰的函数,不能额外传入其他参数,所以这里利用闭包思想,使用闭包嵌套方法,利用一个新的函数来返回装饰器,在新函数中传入参数即可
(2)带参装饰器代码如下:
def return_zsq(char): def zsq(func): def inner(): print(char * 10) func() return inner return zsq # def zsq1(func): # def inner(): # print("*" * 10) # func() # return inner @return_zsq("&") # @zsq1 def print_cont(): print("我是谁?") print_cont()