引入
在web开发中,我们希望我们的视图函数只负责业务逻辑就好了,这个代码越精炼越好,然而实际上很多页面的请求必须登陆了才能返回,因此大多数页面在请求之前我们都要先判断一下是否登录了,没有登陆的话还要先转到登录页面。能不能把这部分判断代码和主体业务逻辑分割开来。
能,这就是装饰器模式,装饰器模式就是将一段核心代码封装一下,丰富了它的功能,使之更为强大。不过python相对其它的语言完成装饰器模式更为简洁。
装饰器如何使用
def outer(func):
print('outer_begin')
def inner(*args, **kwargs):
print('inner_begin')
func()
print('inner_end')
print('outer_end')
return inner
@outer
def log():
print('log-----')
print('#########################')
log()
# 结果
outer_begin
outer_end
#########################
inner_begin
log-----
inner_end
python是一门解释型语言,从上往下执行,先打印的是outer_begin,outer_end,在python里面函数名带上小括号才是调用,才会真的执行。也就是说,函数正主还没开始执行呢,outer函数就已经跑了一遍。
python解释器遇到@outer,会将下面的log函数装饰一下,将log当做参数传到outer函数里面,也就是说装饰器的参数必须是个函数,在outer内部定义了一个内部函数inner,真正的log是在inner内执行的。也就是说outer函数用inner函数把log函数包裹了一下。outer函数最后返回了inner函数,只返回了一个函数名是不会执行的。从此以后在这个可执行文件里面,但凡我们调用log函数的时候,真正执行的是inner函数,怎么证明呢,python有个内置字段__name__可以获取当前对象的名字。
print(log.__name__)
# 输出
inner
说明现在的log已经变成了inner。而这一切在这个文件的代码真正执行以前就已经完成了替换,outer_begin,outer_end就是明证。而inner_begin,log-----,inner_end分别代表,核心代码执行之前的准备工作,核心逻辑,收尾工作。这就是一个简单的装饰器。
一般的,outer_begin,outer_end这两块是没有的,装饰器的形式是这样的
def outer(func):
def inner(*args, **kwargs):
print('inner_begin')
func()
print('inner_end')
return inner
多个装饰器的执行顺序
def outer1(func):
def inner1(*args, **kwargs):
print('inner1_begin')
func()
print('inner1_end')
return inner1
def outer2(func):
def inner2(*args, **kwargs):
print('inner2_begin')
func()
print('inner2_end')
return inner2
@outer1
@outer2
def log():
print('log-----')
log()
# 结果
inner1_begin
inner2_begin
log-----
inner2_end
inner1_end
执行的顺序是,核心代码执行之前,从上到下执行,核心代码执行以后,从下向上执行