今天写后台接口的登录逻辑的时候,遇到了对登录状态的处理,用户登录之后服务器返回给用户token,用户每次调用需要登录的API的时候,就可以根据这个token判断用户是否登录,登录是否过期啥子的了。但是每个路由都对token进行一次验证着实太麻烦了,,而我在java中知道有装饰者模式可以解决这个问题,,所以我查了下,发现python的装饰器也可以解决,而且它也是一个非常重要的东西,所以我就学了下,这里把自己目前的理解写出来,做个记录,纪念我充实的一天。。。。。。
准备知识
1.python函数中可以创建函数
对,没错,就是函数中创建函数,理论上可以一直嵌套
def test():
print("来做个加法叭")
x=1
y=2
def add(a,b):
return a+b
print(add(x,y))
test()
结果:
2.一切皆为对象,函数也是
顾名思义,一切都是对象,函数也是!
def test():
return "一切都是对象!"
a = test
print(type(a))
print(a())
结果:
我们把函数test()当成对象赋给了a,可以发现,我们执行a时和执行test时,没啥区别。
3.函数可以当成参数
由上面可以知道,一切都可是对象,函数也是,,所以函数也可以当成别的函数的参数啦
def wrap(fun):
print("嘿嘿,我在fun前面执行")
print(fun())
print("嘿嘿,我在fun后面执行")
def my():
return "我就是一个卑微的被当成参数的函数"
wrap(my)
结果:
装饰器基本功能
装饰器的功能嘛,就是装饰用的呗,你看,一般的照片不都有个框子把它装起来么,框子上面都有花边撒,花边就是装饰用的。装饰器也是一样的,当你的函数执行之前要处理或者验证啥子事情的时侯,就可以用装饰器来标记啦。
就拿我开头说的,,我的每个API的函数执行之前,我都要知道它有没有收到token,,我要是每个函数前面都写一遍认证的代码,,我可能要疯。。所以只要用上装饰器,就ok啦。
装饰器的实现
结合刚刚的准备知识,我们可以发现把那3点特性结合起来,就可以实现装饰器的功能啦
def decorator(fun): #接收要装饰的函数
def wrap(): #在decorator中新建wrap函数,来执行逻辑,进行“装饰”
print("嘿嘿,我在fun前面执行")
print(fun())
print("嘿嘿,我在fun后面执行")
return wrap #返回这个定义好的函数
def my():
return "我就是一个卑微的被当成参数的函数"
a = decorator(my)
a()
结果
这样,我们就可以说,把my()函数装饰起来了。可是每次都这样写着实麻烦死了。
但是python里有快速的方法实现:@
def decorator(fun): #接收要装饰的函数
def wrap(): #在decorator中新建wrap函数,来执行逻辑,进行“装饰”
print("嘿嘿,我在fun前面执行")
print(fun())
print("嘿嘿,我在fun后面执行")
return wrap #返回这个定义好的函数
@decorator #给my函数加上装饰器decorator
def my():
return "我就是一个卑微的被当成参数的函数"
my()
结果:
嘿嘿,是不是一样的效果?这样就可以大量的简化我们的代码了。
真是太妙了,简直是妙蛙种子进了米奇妙妙屋——妙到家了。
扩展
装饰器的蓝本规范
from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
if not can_run:
return "Function will not run"
return f(*args, **kwargs)
return decorated
@decorator_name
def func():
return("Function is running")
can_run = True
print(func())
# Output: Function is running
can_run = False
print(func())
# Output: Function will not run
同时它也可以写成类
from functools import wraps
class logit():
def __init__(self,x):
print(x)
def __call__(self,func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
return func(*args, **kwargs)
return wrapped_function
@logit("你好")
def a():
print("AAAAA")
a()
这里的__call__是python的类的一种特殊方法,和__init__类似,感兴趣的可以查下。它调用类名()
的时侯触发。
它可以用来打印日志:
class logit():
def __init__(self):
self.count=0
def __call__(self,func):
@wraps(func)
def wrapped_function(*args, **kwargs):
self.count+=1
log_string = func.__name__ + " was called,the count is"
print(log_string,self.count)
return func(*args, **kwargs)
return wrapped_function
@logit()
def a():
print()
while True:
a()
time.sleep(2)