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