1、一些python的知識
一、偏函數
def add(x, y, z): print(x + y + z) # 本來的寫法:x,y,z能夠傳任意數字 add(1,2,3) # 若是我要實現一個功能,這三個數中,其中一個數必須是3 # 咱們就可使用偏函數來幫着咱們傳參 from functools import partial # partial:給add這個函數固定傳一個數字 3 new_add = partial(add, 3) # 所以新的函數只須要傳2個參數 new_add(1,1) new_add(1,2) # 偏函數:就是幫咱們給一個函數固定一個參數 # new_add(x1, x2) --> add(3, x1, x2)
二、類的兩個雙下方法
1. __getattr__:對象獲取屬性值的時候觸發 2. __setattr__:對象設置屬性值的時候觸發 3.示例 class A(object): def __init__(self): # self.name = {} # 初始化的時候,給這個對象設置一個屬性名爲name,值爲空的字典 object.__setattr__(self, "name", {}) def __getattr__(self, item): print("getattr: ", item) def __setattr__(self, key, value): print("setattr: ", self.name) print("setattr: ", key, value) self.name[key] = value print("setattr: ", self.name) # 實例化,調用__init__ a = A() # 獲取對象某個屬性的值,會調用__getattr__ # 若是A這個類沒有__getattr__,就會去執行父類的__getattr__ # 可是嚴謹的__getattr__是:若是你沒有這個屬性,就會給你報錯 # 咱們能夠在A類重寫__getattr__,可讓它不報錯 a.xxx # getattr: xxx # 給對象的某個屬性設置值,會調用__setattr__ # 執行的邏輯跟__getattr__同樣,A類沒有就去調用父類的 a.xxx = '小明' # 首先打印name字典的默認值:是個空字典 setattr: {} # setattr的key是左邊的變量,value是右邊的值:setattr: xxx 小明 # 打印self.name這個字典:setattr: {'xxx': '小明'}
2、Flask上下文管理
Flask的上下文管理咱們能夠理解爲一個生命週期
也就是請求進來到請求出去一共作了哪些事情
首先咱們知道項目啓動執行了app.run()方法,調用了werkzeug的run_simple()方法
run_simple(host, port, self, **options) 這時候的self就是咱們的app
run_simple會執行self(),也就是app(), 那麼app = Flask() 因此會走Flask的__call__方法前端
那麼__call__作了什麼呢
environ是咱們請求來的原始數據~當成參數傳遞給了request_context方法python
進入這個RequestContext對象flask
這是初始化這個類作的一些事情
在這裏從新封裝了request, 以及給session 賦值了 None
也就是說:
ctx = RequestContext(app, environ)
ctx.request 是從新封裝的request
ctx.session = Nonecookie
繼續session
執行了_request_ctx_stack.push(ctx)
也就是說_request_ctx_stack它把咱們的ctx對象push到了一個地方
咱們的ctx這個對象裏面有request以及session等數據結構
這個初始化方法就是剛纔python類的雙下方法__setattr__
就是給Local類初始化了兩個屬性 __storage__ = {} __ident_func__ = get_identapp
咱們繼續看LocalStark中push方法作了什麼ide
如今回去看wsgi_app裏的ctx.push(),到這裏,它就走完了,接下來就要走視圖
那到這裏咱們能夠經過什麼樣的方法在咱們視圖中拿到這個request對象呢
request在ctx對象裏能經過ctx.request獲得,那咱們怎麼獲得ctx呢
ctx被LocalStack對象放入到Local中了函數
![](http://static.javashuo.com/static/loading.gif)
from flask import Flask from flask import globals app = Flask(__name__) @app.route("/") def index(): ctx = globals._request_ctx_stack.top print(ctx.request.method) return "index" if __name__ == '__main__': app.run()
3、Flask上下文管理(續)
這個request:
from flask.globals import _request_ctx_stack
ctx = _request_ctx_stack.top
request = ctx.requestpost
和這個request:
from flask import request
兩個request有什麼區別?
其實咱們導入的request跟咱們上面拿到的request是同樣的。
下面看看怎麼直接拿request
reqeust是LocalProxy這個類的實例化對象,參數是一個偏函數,
那當咱們調用request.method 等方法的時候走的是LocalProxy這個類的__getattr__方法
這裏的_get_current_object()至關於咱們偏函數的執行
所以,直接導入的request也是經過LocalStack方法去Local中取ctx對象
而後經過getattr 找到ctx.request,
也就是說這個LocalProxy就是一個幫助咱們取值的代理,讓咱們的取值變的更加簡單
這個代理經過偏函數來綁定參數,
ctx中封裝了request,以及session,只不過到這裏咱們的session依然是空的。
4、session的實現原理
_request_ctx_stack.push(self)走完後,會繼續走這個
也就是說,請求進來把ctx放入Local中後,從前端解密了cookie,而後把解密數據好的數據給了self.session
繼續走
那麼session的實現機制:
1. 請求進來獲取cookie的值
2. 解密cookie轉換成字典(沒有cookie就是空字典)賦值給ctx.session
3. 當請求走的時候把session的數據加密
4. 設置cookie
5、應用上下文管理
應用上下文和請求上下文的原理和源碼是同樣的
也就是說,咱們請求上下文和應用上下文,分別創建了兩個Local對象
兩個Local對象數據結構都是同樣的,那麼請求上下文和應用上下文爲何要分開存放呢
由於咱們寫離線腳本的時候須要用到!
小結:
也就是說能夠導入請求上下文的request, session和應用上下文的g, current_app
from flask import Flask, request, session, g, current_app
6、全局對象g
咱們說應用上下文裏封裝了g對象,那麼這個g對象是什麼呢
1. Flask中g的生命週期?
咱們講這麼多上下文管理,咱們知道請求進來會爲每一個請求在Local中創建一個獨立空間
也就是在應用上下文的Local對象中創建了一個g對象,當請求走的時候就會刪除
因此g的生命週期是一次請求的進來到離開。
2. g和session有什麼區別?
session有cookie,下次請求進來的時候能帶數據過來
3. g和全局對象有什麼區別?
全局變量,是在項目啓動建立的,直到項目中止纔會銷燬
不管多少請求進來均可以訪問全局變量
而咱們的g對象通常狀況用於before_request中設置值,只爲這一次請求創建全局變量
4. Demo
from flask import Flask, request, session, g, current_app from flask.globals import _request_ctx_stack app = Flask(__name__) @app.before_request def auth(): g.xxx = "小明" @app.route("/") def index(): ctx = _request_ctx_stack.top print(ctx.request) print(ctx.request.method) print(current_app) # request.xxx的執行過程 # 1. request --> LocalProxy(偏函數) # 2. request.xxx --> LocalProxy __getattr__ # 3. __getattr__ --> getattr(偏函數的執行,xxx ) # 4. 偏函數--> _request_ctx_stack.top.request print(g.xxx) return "INDEX" if __name__ == '__main__': app.run()