• flask 请求上下文


    一篇引用大牛的
    https://www.cnblogs.com/zhaopanpan/p/9457343.html
    ### 线程安全  

    ```python
    # 线程不安全
    class Foo(object):
    pass

    foo = Foo()
    foo.num = 1

    import time
    import threading

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

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

    # 线程安全
    from threading import local
    class Foo(local):
    pass

    foo = Foo()
    foo.num = 1

    import time
    import threading

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

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

    # 开辟新空间 - 浪费了部分资源 - 速度保证 - 保证安全
    """
    {
    16232:[request],# 123
    17164:[request],# 456
    9088: [request],# 567
    16084:[request],# 789
    }

    Threading.local
    Flask 上下文机制就是使用的 Threading.local
    线程进来 开辟一个空间给这个线程,线程操作的所有任务,都会复制一份儿到空间中
    """
    ```

    ### 栈 Stack

    ```python
    # Stack
    class MyStack(object):
    data = []

    def __setattr__(self, key, value):
    self.push(key,value)

    def push(self,key,value):
    self.data.append({key:value})

    def top(self):
    return self.data.pop()

    my_stack = MyStack()

    my_stack.name = 666 # [{name:666}]
    my_stack.name = 777 # [{name:666},{name:777}]

    print(my_stack.data)

    # my_stack.push(666)
    # my_stack.push(777)
    # my_stack.push(888)
    #
    # print(my_stack.top(),my_stack.data)
    # print(my_stack.top(),my_stack.data)
    # print(my_stack.top(),my_stack.data)
    ```



    ### 局部的栈 LocalStack

    ```python
    # LocalStack 安全的 栈
    from threading import get_ident # 获取当前线程的 id
    import threading


    class MyLocalStack(object):
    storage={}
    def push(self,item):
    try:
    self.storage[get_ident()].append(item)
    except:
    self.storage[get_ident()]=[item]

    def top(self):
    return self.storage[get_ident()].pop()


    my_local_stack = MyLocalStack()

    import time
    def go(i):
    my_local_stack.push(i)
    time.sleep(1)
    # my_local_stack.top()


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


    print(my_local_stack.storage)
    ```



    ## flask 的 请求上下文

    + ## werkzeug

    + flask 的 wsgi

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

    @Request.application
    def app(environ):
    print(environ)
    return Response("200OK")

    run_simple("0.0.0.0",9527,app)

    ```

    ```python
    from flask import Flask
    app = Flask(__name__)

    if __name__ == '__main__':
    app.run(host='0.0.0.0',port=7088)
    app.__call__
    app.wsgi_app

    ```

    ### 上文

    1. 从 **`run()`** 开始

    + 进入源码 其中的 >> `self = app = Flask()`

    + 导入了 `from werkzeug.serving import run_simple` 执行了 `run_simple(host, port, self, **options)` 方法

    + 看这一句 `run_simple("0.0.0.0",9527, app) ` 也就是说

    self 会执行 >> `self = app = Flask() = self()`

    + 也就 == app() 对象() 执行 类的 `__call__()` 方法



    2. `__call__() ` 执行了 `self.wsgi_app(environ, start_redponse)` **environ = request 原始信息**



    3. 进入 `app.wsgi_app`

    + `def wsgi_app(self, environ, start_response):` >> self = app = Flask()

    + self 执行了这个方法 `ctx = self.request_context(environ)` 方法中执行了 一个类 `RequestContext(self, environ)` ctx.py文件中 >> 这个对象中 包含了 两个 值 requset/session

    ctx = requsetcontext --> requset/session

    + 在这个类中 的 初始化方法 中 `def __init__(self, app, environ, request=None):` >> self = RequestContext ->request/session app = Flask request=None 执行方法 `request = app.request_class(environ)` 这个方法将 environ 序列化 出了 request对象 就是可以使用 request.method requset.form ... 方法 了

    + 执行ctx.push() 方法

    4. ctx.push() 方法



    + 方法中执行了 `top = _request_ctx_stack.top` --> `_request_ctx_stack = LocalStack()` 实例化时的 `__init__` 方法中 初始化了 两个 对象 >> `self._local = {"__storage__": {}, "__ident_func__": get_ident}` >`get_ident` 获取线程 或携程的 id 并没有执行

    + `_request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`

    + `.top ` 方法 执行了 `self._local.stact[-1]` .stack 调用 Local(object): 对象的 `__getattr__(self) 方法`

    + 方法中 调用 `self.__storage__[self.__ident_func__()][name]` 也就是从

    `{"__storage__": {}, "__ident_func__": get_ident}` 中的 `__storage__` 中通过key 取值 此时 `__storage__` 中为 空字典 报错 抛出异常 `AttributeError(name)` 这个异常在上面的 top 方法中 被捕获 返回 一个 None 返回 **top = None** 之后的 if 判断不成立

    + 之后又执行了 `_request_ctx_stack.push(self)` 代码 其中的 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`

    + 执行了.push(self) 方法 这个self = ctx = requset/session 进入 push() 方法

    + `def push(self, obj)`这里面的 self 是 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` obj = ctx = requset/session 执行 : ` rv = getattr(self._local, 'stack', None)` `self._local = {"__storage__": {}, "__ident_func__": get_ident}` rv = None -> if判断 执行` self._local.stack = rv = [] rv.append(obj) ` 走对象的 `__setattr__(self,name,value)`方法 返回 =>> `{"__storage__": {7088:{"stack": rv=[] }}, "__ident_func__": get_ident}`

    + 返回 rv.append(obj) ==>`{"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}` `rv=[ctx=>request/session] ` 并没有接收返回值 执行完之后 `self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}`



    ### 下文

    + 使用时才执行

    ```python
    @app.route("/")
    def login():
    if requset.method =='POST':
    ...
    # requset.method 之后启动下文
    ```

    + 进入 request

    ```python
    # partial 偏函数
    request = LocalProxy(
    partial(
    _lookup_req_object,
    'request'
    )
    )
    ```

    + `_lookup_req_object`

    ```python
    def _lookup_req_object(name):
    top = _request_ctx_stack.top
    # _request_ctx_stack = self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident} 调用.top 方法
    if top is None:
    raise RuntimeError(_request_ctx_err_msg)
    return getattr(top, name)
    ```

    + .top 中 执行了 `self._local.stack[-1]`

    ```python
    # 执行 self._local的 __getattr__ 方法
    def __getattr__(self, name):
    try:
    return self.__storage__[self.__ident_func__()][name]
    except KeyError:
    raise AttributeError(name)

    # 返回了 [ctx => request / session ]
    ```

    执行 [-1] 得到 `ctx => request / session`

    + `top = ctx => request / session`

    + `getattr(top, name)` name = request 从偏函数传递过来的 方法 得到了 一个 request 对象 及 request 的真身

    + 查看` LocalProxy(偏函数没被执行的 )` 实例化 执行`def __init__(self, local, name=None):` local = request 的偏函数

    ```python
    def __init__(self, local, name=None):
    object.__setattr__(self, '_LocalProxy__local', local)
    object.__setattr__(self, '__name__', name)
    if callable(local) and not hasattr(local, '__release_local__'):
    # "local" is a callable that is not an instance of Local or
    # LocalManager: mark it as a wrapped function.
    object.__setattr__(self, '__wrapped__', local)
    ```

    + request.method 执行 .方法 调用 `__getattr__()` 执行 `getattr(self._get_current_object(), name)`

    ```python
    def _get_current_object(self):
    if not hasattr(self.__local, '__release_local__'):
    return self.__local()
    try:
    return getattr(self.__local, self.__name__)
    except AttributeError:
    raise RuntimeError('no object bound to %s' % self.__name__)
    ```

    `__local = local = requset偏函数执行 = requset`

    + `getattr(request, name)` name = method

    + ### 查看 LocalProxy 类 包含了 所有面向对象的 特殊方法

    ### 应用上下文

    + 会在 离线脚本 的时候使用

    + 从 `app.wsgi_app` 中 找到 `ctx.push()` 的方法

    + `app_ctx = _app_ctx_stack.top` 这个 就是应用上下文

    ```python
    app_ctx = _app_ctx_stack.top
    if app_ctx is None or app_ctx.app != self.app:
    app_ctx = self.app.app_context()
    app_ctx.push()
    self._implicit_app_ctx_stack.append(app_ctx)
    else:
    self._implicit_app_ctx_stack.append(None)
    ```



    1. `_app_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`
    2. `.top` 方法 返回的还是 None
    3. `app_ctx = None`

    + `app_ctx = self.app.app_context()` 序列化 app 得到 AppContext(app,g) -> requestcontext(request/session)

    + `app_ctx.push()` 得到 `self._local = {"__storage__": {7088:{"stack": [app_ctx(app, g)] }}, "__ident_func__": get_ident}` g会在 离线脚本 的时候使用

    `current_app = LocalProxy(_find_app)` = app = Flask()

    ```python
    def _find_app():
    top = _app_ctx_stack.top # 拿到 app_ctx(app,g)
    if top is None:
    raise RuntimeError(_app_ctx_err_msg)
    return top.app # 返回一个 app 独立的 app
    ```

    请求结束之后执行 pop 方法 删除缓存

    `g = LocalProxy(partial(_lookup_app_object, 'g'))`


  • 相关阅读:
    第三周作业
    第二周作业 编程总结
    编程总结二 求最大值及其下标
    编程总结一 查找整数
    第十周课程总结
    第九周课程总结&实验报告(七
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
    第六周&java实验报告四
    第五周的作业
  • 原文地址:https://www.cnblogs.com/zhangchen-sx/p/10588088.html
Copyright © 2020-2023  润新知