zoukankan      html  css  js  c++  java
  • Flask上下文管理、session原理和全局g对象

    一、一些python的知识

    1、偏函数

    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)

    2、类的两个双下方法

    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': '小明'}

    二、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方法


    进入这个RequestContext对象


    这是初始化这个类做的一些事情
    在这里重新封装了request, 以及给session 赋值了 None
    也就是说:
    ctx = RequestContext(app, environ)
    ctx.request 是重新封装的request
    ctx.session = None

    继续


    执行了_request_ctx_stack.push(ctx)
    也就是说_request_ctx_stack它把我们的ctx对象push到了一个地方
    我们的ctx这个对象里面有request以及session等


    这个初始化方法就是刚才python类的双下方法__setattr__
    就是给Local类初始化了两个属性    __storage__ = {}            __ident_func__ = get_ident

    我们继续看LocalStark中push方法做了什么


    现在回去看wsgi_app里的ctx.push(),到这里,它就走完了,接下来就要走视图
    那到这里我们可以通过什么样的方法在我们视图中拿到这个request对象呢
    request在ctx对象里能通过ctx.request得到,那我们怎么得到ctx呢
    ctx被LocalStack对象放入到Local中了

    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()
    获取ctx

    三、Flask上下文管理(续)

    这个request:
      from flask.globals import _request_ctx_stack
      ctx = _request_ctx_stack.top
      request = ctx.request


    和这个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依然是空的。

    四、session的实现原理

     _request_ctx_stack.push(self)走完后,会继续走这个

    也就是说,请求进来把ctx放入Local中后,从前端解密了cookie,然后把解密数据好的数据给了self.session
    继续走

    那么session的实现机制:
      1. 请求进来获取cookie的值
      2. 解密cookie转换成字典(没有cookie就是空字典)赋值给ctx.session
      3. 当请求走的时候把session的数据加密
      4. 设置cookie

    五、应用上下文管理

     应用上下文和请求上下文的原理和源码是一样的

    ctx.push()

    也就是说,我们请求上下文和应用上下文,分别建立了两个Local对象
    两个Local对象数据结构都是一样的,那么请求上下文和应用上下文为什么要分开存放呢
    因为我们写离线脚本的时候需要用到!

    小结:
    也就是说可以导入请求上下文的request, session和应用上下文的g, current_app
    from flask import Flask, request, session, g, current_app

    六、全局对象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()

    七、Flask上下文管理图解

  • 相关阅读:
    Hammer.js--转载自李林峰的园子
    nodejs--模块
    gruntjs
    玩转github----1
    模块化开发--sea.js
    事件委托
    css兼容问题
    轮播图
    Spring整合Hibernate 二
    Spring整合Hibernate 一
  • 原文地址:https://www.cnblogs.com/Zzbj/p/10207128.html
Copyright © 2011-2022 走看看