• Flask第十二篇- flask中的CBV、werkzeug+上下文初步解读、偏函数和线程安全


    一、flask中的CBV

      对比django中的CBV,我们来看一下flask中的CBV怎么实现?

    复制代码
      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方法中指定。

    二、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/上,如下:

      浏览器访问该网址控制台显示的网址,输出结果如上图,且页面显示返回结果'200 ok'。由此说明视图函数app执行了,再看我们之前写的代码:

    复制代码
      from flask import Flask, ...
    
      app = Flask(__name__)
    
      ......
      
      app.run(debug=True)         # app 是flask的实例化对象
    复制代码

      这里重点分析app.run() 都干了什么?

      首先,执行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方法,源码如下:

     

      request_context() 方法源码如下,其中的self仍然是Flask的实例化对象app:

     

      RequestContext是一个类,它的__init__方法源码如下:

     

      本篇暂时解读到这里,下篇继续解读。

    三、偏函数和线程安全

    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()
    
      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()
    复制代码

        总结:完美解决问题,采用了以空间换取时间的方法,为每个线程保存了一块空间,使线程之间互相不受影响。

  • 相关阅读:
    JVM原理---------------1.开篇
    mysql开启事务的方式,命令学习
    mysql中的锁
    mysql索引底层原理
    mysql的常见存储引擎与常见日志类型,以及4种线程的作用
    Mutex
    委托和匿名委托
    线程通信
    同步锁
    [ValidateInput(false)]
  • 原文地址:https://www.cnblogs.com/xintiao-/p/10447051.html
Copyright © 2020-2023  润新知