目录
前言
本来不想写,奈何网上的教程太傻。
其实很多时候写教程都是因为这个原因,到底是怎么做到把这么简单的概念写的乱七八糟的???
装饰器的概念
如果你使用过Django,那你可能已经见过装饰器了,最著名的Django装饰器应该长这样:
@csrf_exempt
事实上,装饰器仍然是一个函数(其实是函数[函数([函数])]),但它的使用形式如同上图。装饰器的作用是“装饰”一个函数,在使用装饰器之后接的那个函数(下一行的函数)就是被装饰的函数。
装饰器函数的书写
一个最简单的装饰器形如下所示:
def decorator(func):
def deco_func([args1,args2...]]): #args为参数表,是被修饰函数中的参数,一个不多一个不少
do_sth
return func([args1,args2...])
return deco_func
可以看到,装饰器本身只接受一个参数,那就是被这个装饰器修饰的函数。装饰器中嵌套了另一个函数,由它来接收被修饰函数中的参数表(一个不多一个不少),而被修饰的函数在这个“二级函数”中执行。最后,装饰器将返回二级函数本身。
不过,并不是所有情况下被修饰的函数都要被执行的,例如如下情况,装饰器在输入函数的参数为1时返回None:
def deco2(func):
def decor(a):
if(a==1):
return None
else:
return func(a)
return decor
@deco2
def funv(a):
pass
带参数的装饰器
装饰器当然可以带参数,但在带有参数时,装饰器外面需要再嵌套一层函数用以接收装饰器使用时传入的参数,而在调用时,只需要在调用语句后面加上括号传递参数即可:
def deco3(arg1): #接收装饰器参数
def deco3_1(func): #接收被装饰函数
def decor(a,b,c): #接收被装饰函数传入的参数
print("decorator arg is {0},deco args are {1} {2} {3}.".format(arg1,a,b,c))
func(a,b,c)
return decor #逐层返回到最外层
return deco3_1
@deco3("decorator!")
def func(a,b,c):
print(a+b+c)
可变参数
很多时候,被修饰的函数和装饰器接收的参数都是不固定的。在这种情况下,我们可以使用*args和**kwargs来读取变化的参数(使用过C系列语言的读者对这两个参数应该不陌生),其中*args传入一个顺序参数的元组(比如func(a,b)则传入(a,b)),**kwargs传入一个指定参数名的参数字典(比如func(a=a1,b=b1)则传入{a=a1,b=b1})。
#多个装饰器同时装饰一个函数时
一个小tips。我通过以下代码以及其运行结果来说明它们的运作顺序:
def deco1(func):
def decor(a):
print("before deco1 decorator.")
func(1)
print("after deco1 decorator.")
return decor
def deco2(func):
def decor(a):
print("before deco2 decorator.")
func(2)
print("after deco2 decorator.")
return decor
@deco1
@deco2
def func(a):
print("func run with args: {0}".format(a))
func("")
#输出如下:
##before deco1 decorator.
#--第一个装饰器执行前代码先执行
##before deco2 decorator.
#--第二个装饰器执行前代码后执行
##func run with args: 2
#--函数体,可以看到调用只有一次,传参是以最后的装饰器为准
##after deco2 decorator.
#--第一个装饰器执行后代码先执行
##after deco1 decorator.
#--第二个装饰器执行后代码后执行