Python装饰器
1、简介
本质:
Python的装饰器就是一个闭包。
目的:
简化代码操作
2、使用装饰器的原则:不改变被装饰函数的属性等性质
-
使用中间人
g对象
帮助传递参数 -
使用内层装饰器
@functools.wraps(view_func)
回复被装饰函数的属性等性质(举例2)
3、 举例1 :定义验证登录状态的装饰器
# 使用中间人g对象作为装饰器和被装饰函数中的参数传递者
from
flask
import
session
,
jsonify
,
g
from
myihome
.
utils
.
response_code
import
RET
import
functools
# python的内置模块,存放函数工具
# 闭包:外层函数一般就是定义为被装饰的函数(view_func(例如这里是:set_user_avatar))"的@外层函数"
def
login_required
(
view_func
)
:
# 内层函数一般定义为wrapper,并且由于传递的参数不确定,使用*args, **kwargs待定
# @functools.wraps(view_func)这个函数装饰器专门是用来装饰内层函数的,
# 1参数:外层函数接受的参数,直接传给里面的就可以了,
# 2意义:内层装饰器加上之后会改变一些特性:functools的wraps会将wrapper相关的属性和名字恢复为view_func的属性和名字,参考博客的例子2
@functools
.
wraps
(
view_func
)
# 在写装饰器的时候需要习惯将这个内层装饰器补上,避免改变被装饰函数的特性
def
wrapper
(
*
args
,
**
kwargs
)
:
# 判断用户的登录状态
user_id
=
session
.
get
(
"user_id"
)
# 如果用户是登录的,执行视图函数
if
user_id
is
not
None
:
# g对象的应用,保存user_id,让其作为参数传递对象,在视图函数中可以通过g对象获取保存数据
g
.
user_id
=
user_id
return
view_func
(
*
args
,
**
kwargs
)
else
:
# 如果未登录,返回未登录的信息
return
jsonify
(
errno
=
RET
.
SESSIONERR
,
errmsg
=
"用户未登录"
)
return
wrapper
# 使用中间人g对象作为装饰器和被装饰函数中的参数传递者,g对象就是提供来保存数据的
# 在一次请求之中如果涉及到多个函数请求参数的时候就可以使用g对象来传参数
@login_required
def
set_user_avatar
(
)
:
# 本来是可以直接操作session获取user_id的,
# 但是使用的装饰器里面已经获取到了user_id,由装饰器的原则,不可能变成 def set_user_avatar(user_id):的,所以可以使用中间人g对象传递过来,不必重复操作一遍
# user_id = session.get("user_id")
user_id
=
g
.
user_id
pass
# set_user_avatar() 的执行就是执行wrapper-> wrapper() 直接传递参数到wrapper()里面
4、
举例2:
内层装饰器
@functools.wraps(func)
的作用
①首先:未加上装饰器:
def
login_required
(
func
)
:
def
wrapper
(
*
args
,
**
kwargs
)
:
pass
return
wrapper
def
test
(
)
:
"""test python"""
pass
print
(
test
.
__name__
)
print
(
test
.
__doc__
)
Python中万物皆对象,直接打印出函数test()的名字和说明文档:
test
test python
②加上装饰器:
def
login_required
(
func
)
:
def
wrapper
(
*
args
,
**
kwargs
)
:
pass
return
wrapper
@login_required
def
test
(
)
:
"""test python"""
pass
# test -> wrapper :执行test(), 实质是执行wrapper()
print
(
test
.
__name__
)
# wrapper.__name__
print
(
test
.
__doc__
)
# wrapper.__doc__
打印的结果为:
wrapper
None
可见已经改变test()的属性了,违反了装饰器的原则。
③加上内层函数装饰器:
import
functools
def
login_required
(
func
)
:
@functools
.
wraps
(
func
)
def
wrapper
(
*
args
,
**
kwargs
)
:
pass
return
wrapper
@login_required
def
test
(
)
:
"""test python"""
pass
# test -> wrapper
print
(
test
.
__name__
)
# wrapper.__name__
print
(
test
.
__doc__
)
# wrapper.__doc__
打印结果为:
test
test python
可见被装饰函数的属性被恢复了。
参考代码及项目URL:
https://github.com/too-hoo/myiHome/blob/master/myihome/utils/commons.py