Flask中的CBV和上下文初步解讀

     一 . flask中的CBV      

   相對於Django中的CBV,讓咱們來看看flask中的CBV是如何實現的 ? html

  from flask import Flask, render_template, url_for, views

  app = Flask(__name__)

  class Login(views.MethodView):
    def get(self):
      print(url_for("my_login"))     # /login
      return render_template("login.html")

    def post(self):
      return "login success"

  app.add_url_rule("/login", view_func=Login.as_view("my_login"))

  if __name__ == '__main__':
    app.run(debug=True)

   注意:視圖類中定義了哪些方法,就能夠容許哪一種方式的請求,也能夠經過指定參數methods=["GET","POST"],指定參數時能夠在視圖類中指定,也能夠在add_url_rule方法中指定。flask

     二 . werkzeug + 上下文初步解讀        

       經過查看源碼,咱們知道app.run() 方法實際上是執行了run_simple() 方法,源碼以下:瀏覽器

      

  咱們能夠經過下面一段代碼探究run_simple() 方法都作了什麼?安全

  from werkzeug.serving import run_simple
  from werkzeug.wrappers import Request, Response

  @Request.application
  def app(req):
    print(req.method)    # GET
    print(req.path)     # /
    return Response('200 ok')

  run_simple('0.0.0.0', 5000, app)

  運行代碼,發現服務運行在http://0.0.0.0:5000/上,以下:session

      

  瀏覽器訪問該網址控制檯顯示的網址,輸出結果如上圖,且頁面顯示返回結果'200 ok'。由此說明視圖函數app執行了,再看咱們以前寫的代碼:app

  from flask import Flask, ...

  app = Flask(__name__)

  ......
  
  app.run(debug=True)         # app 是flask的實例化對象

  這裏重點分析app.run() 都幹了什麼?ide

  首先,執行app.run() 時,源碼中顯示執行了執行run_simple() 方法,源碼中run_simple() 方法的參數是run_simple(host, port, self, **options) ,這裏重點看第三個參數self,由於app是flask的實例化對象,所以self就是指flask的實例化對象app,而上例中咱們知道當有請求進來的時候,執行了app(),咱們知道函數加括號是執行,而對象加括號會自動執行__call__方法,也就是說app.run() 實際上是監聽了flask類中的__call__方法,經過解讀源碼咱們發現__call__方法內容以下:函數

      

  __call__方法中執行了wsgi_app方法,源碼以下:post

     

  request_context() 方法源碼以下,其中的self仍然是Flask的實例化對象app:url

     

  RequestContext是一個類,它的__init__方法源碼以下:

     

   初步解讀到此結束,下一篇-- flask的請求上下文源碼解讀

 

     三 . 偏函數和線程安全       

 1 . 偏函數就是把前邊的值傳進來可是不執行 

  1) . 示例一 : 

  from functools import partial

  def ab(a,b):
    print(a,b)   # 1 5
    return a+b

  par_ab = partial(ab, 1)          # par_ab是一個新函數,接受了括號中的參數

  print(par_ab)
  # functools.partial(<function ab at 0x00000203FAB01E18>, 1)

  print(par_ab(5))
  # 6
  # par_ab(5)會執行新函數,且partial(ab, 1)中參數1會成爲新函數par_ab的第一個參數,par_ab(5)中的5會成爲第二個參數,新函數的函數體是ab函數

  2) . 示例二 

  from functools import partial

  def ab(a,*args):
    print(a,args)   
    return a

  par_ab = partial(ab, 1, 5, 7, 9)

  print(par_ab)
  # functools.partial(<function ab at 0x0000020396711E18>, 1, 5, 7, 9)
  # 新函數不加括號不執行

2 . 線程安全 

  1) . 示例一 

  import time

  class Foo(object):
    pass

  foo = Foo()

  def add(i):
    foo.num = i
    time.sleep(1)
    print(foo.num)

  for i in range(20):
    add(i)

  總結 : 等待時間長

  2) . 示例二  : 開啓線程 

  import time
  import threading

  class Foo(object):
    pass
  
  foo = Foo()

  def add(i):
    foo.num = i
    time.sleep(1)
    print(foo.num, i)

  for i in range(20):
    th = threading.Thread(target=add, args=(i,))
    th.start()

  總結 : 數據不安全 

  3) . 示例三 

  import time
  import threading
  from threading import local

  class Foo(local):
    pass

  foo = Foo()
"""
{
    7172:[request,session],
    8076:[request,session],
    5784:[request,session],
}
"""


# 線程安全,是在不帶鎖的狀況下,複製出了無數個對象,
# 當前這一個線程就行操做,操做本身的對象.拿的時候也拿本身的對象,不拿公共的對象.
# 由於request和session屬於公共變量
# 就至關因而一個大字典,每個線程的ID對應本身的一個空間,放到字典中.
# 每個線程進來的時候,從本身的空間中取值或更改值.
# 這樣就能夠在多個線程同時執行的時候能夠保證數據安全的前提下,還能夠保證速度
# 用空間換時間,確保線程在同時開啓的狀況下不會互相影響

  def add(i):
    foo.num = i
    time.sleep(1)
    print(foo.num, i, threading.current_thread().ident)

  for i in range(20):
    th = threading.Thread(target=add, args=(i,))
    th.start()

   總結 : 完美解決問題,採用了以空間換取時間的方法,爲每一個線程開闢了一塊屬於本身的空間,是線程之間互不影響.

相關文章
相關標籤/搜索