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