• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

Karlie24

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

flask-上下文2-梳理顺序

from flask import Flask,request

app = Flask(__name__)

@app.route('/')
def hi():
print(request)
return 'hi'

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


---------------------------------
/////////实例对象能像函数一样传参并被调用,就是__call__()方法的功能。
》〉》如果类中
__call__()无需传参数,则 对象()即会调用该方法。
》〉》如果类中__call__()需传参数,则 对象(参数)即会调用该方法。

app.run()---〉 run_simple(t.cast(str, host), port, self, **options)

self即是app对象,当请求到来时,拿到第三个参数加括号,即app() ???
即进入app.__call__

import sys
class A(object):
    def __init__(self, x):
        print('x in __init__', x)

    def __new__(cls, y):
        print('y in __new__', y)
        return super(A, cls).__new__(cls)

    def __call__(self, z=1):
        print('z in __call__', z)

    def ru(self):
        print('sdfs')


# A('123')('abc')
a = A('1')
if __name__ == '__main__':
    a(1)
    print('aaa')
    a()
    print('aaa')
    a.ru()

# a = A('1')   # a是对象,A是类   init 和new 是生成对象时调用
# print(type(a),'  ...   ',type(A))
# print(type(object))
# a('3')       # call 是对象生成后,使用对象时调用

    print(sys.modules[__name__])
    print(sys.modules[__name__].__file__)
    print(type(sys.modules[__name__].__file__))

---------------------------
/Users/user/data/flask/venv/bin/python /Users/user/data/flask/class22.py
y in __new__ 1
x in __init__ 1
z in __call__ 1
aaa
z in __call__ 1
aaa
sdfs
<module '__main__' from '/Users/user/data/flask/class22.py'>
/Users/user/data/flask/class22.py
<class 'str'>

 

__name__ == '__main__'
app = Flask(__name__)  ---> app = Flask('__main__')   实例化Flask对象,app即是该对象名

进入Flask类
if self.import_name == "__main__":
    fn = getattr(sys.modules["__main__"], "__file__", None)     //--》getattr(x, 'y') is equivalent to x.y.
'''
print(sys.modules[__name__])
print(sys.modules[__name__].__file__)
---

<module '__main__' from '/Users/user/data/flask/class22.py'>

/Users/user/data/flask/class22.py
'''
# 所以得到fn = 当前文件名

    if fn is None:
        return "__main__"
    return os.path.splitext(os.path.basename(fn))[0]
return self.import_name
View Code
app.run()   --->    run_simple   # Start a WSGI application.
       from werkzeug.serving import run_simple
        try:
            run_simple(t.cast(str, host), port, self, **options)
        finally:
            self._got_first_request = False
View Code

 

__call__  
1.app.__call__ ---》 return self.wsgi_app(environ, start_response)
2.app.wsgi_app ---》
        ctx = self.request_context(environ)
        error: t.Optional[BaseException] = None
        try:
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:  # noqa: B001
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)    
View Code
2.1 ctx = self.request_context(environ)    ---》  return RequestContext(self, environ)   ---> RequestContext(app, environ)
  ---> ctx = RequestContext(app,environ)
初始化RequestContext对象
//ctx即是该对象,且其中包含了request对象为其request属性。
class RequestContext:
    """The request context contains all request relevant information.  It is
    created at the beginning of the request and pushed to the
    `_request_ctx_stack` and removed at the end of it.  It will create the
    URL adapter and request object for the WSGI environment provided.

    """

    def __init__(
        self,
        app: "Flask",
        environ: dict,
        request: t.Optional["Request"] = None,
        session: t.Optional["SessionMixin"] = None,
    ) -> None:
        self.app = app
        if request is None:
            request = app.request_class(environ)
        self.request = request
        self.url_adapter = None
        try:
            self.url_adapter = app.create_url_adapter(self.request)
        except HTTPException as e:
            self.request.routing_exception = e
        self.flashes = None
        self.session = session
View Code
app: "Flask",    --对应参数app
environ: dict,   --对应参数environ
self.app = app     # 此时的self是RequestContext对象ctx,并将参数的app对象赋值给 ctx.app
if request is None:
request = app.request_class(environ) ---》 request_class = Request ---》class Request(RequestBase)
                                              --->request = Request(environ)
self.request = request   # ctx.request
self.session = session # ctx.session


2.2 ctx.push()          --- RequestContext的push方法
    def push(self) -> None:
        """Binds the request context to the current context."""
        top = _request_ctx_stack.top
        if top is not None and top.preserved:
            top.pop(top._preserved_exc)

        # Before we push the request context we have to ensure that there
        # is an application context.
        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)

        _request_ctx_stack.push(self)

        if self.url_adapter is not None:
            self.match_request()

        # Open the session at the moment that the request context is available.
        # This allows a custom open_session method to use the request context.
        # Only open a new session if this is the first time the request was
        # pushed, otherwise stream_with_context loses the session.
        if self.session is None:
            session_interface = self.app.session_interface
            self.session = session_interface.open_session(self.app, self.request)

            if self.session is None:
                self.session = session_interface.make_null_session(self.app)
View Code

_request_ctx_stack.push(self) ---》 _request_ctx_stack = LocalStack()


'''
初始化LocalStack对象
    def __init__(self) -> None:
        self._local = Local()
View Code
self._local = Local()

初始化Local对象
'''
_request_ctx_stack.push(self)    ---》  LocalStack.push(ctx)
    def push(self, obj: t.Any) -> t.List[t.Any]:
        """Pushes a new item to the stack"""
        rv = getattr(self._local, "stack", []).copy()
        rv.append(obj)
        self._local.stack = rv
        return rv  # type: ignore
View Code
(
def push(self, obj: t.Any) -> t.List[t.Any]:       # import typing as t
很多人在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参数,返回什么类型的结果。
因此typing作用于提示参数和返回参数类型。
)
rv = getattr(self._local, "stack", []).copy() ---> getattr(x, 'y') is equivalent to x.y || self._local = Local()
                              ---> rv = Local().stack对应的值,如果无stack值则rv = []
rv.append(obj) # obj = ctx ,即添加 ctx至rv

self._local.stack = rv   # 赋值  ---> Local().stack=rv ---> 调用Local的__setattr__方法。 (对象.xx,即调用对象的__setattr__方法)

Local对象初始化
    def __init__(self) -> None:
        object.__setattr__(self, "_storage", ContextVar("local_storage"))
View Code
Local()._storage = ContextVar("local_storage")   ???

ContextVar这个模块提供了一组接口,可用于管理、储存、访问局部Context的状态。
-----
https://blog.csdn.net/weixin_39727934/article/details/111439409
    def __setattr__(self, name: str, value: t.Any) -> None:
        values = self._storage.get({}).copy()
        values[name] = value
        self._storage.set(values)
View Code

values = self._storage.get({}).copy()   ---》

name=stack,value=rv ... 等同于 _storage[ident][stack] = value. ??? https://www.cnblogs.com/zhuleixiao/p/9041066.html
---> 即将value值封装到 Local()._storage[ident][stack] 中 ??? 根据ident值可做不同请求到隔离

(可参考旧版源码,即Local()[ident][stack] = obj, obj=ctx)

 




2.3 执行路由系统方法 print(request)
request: "Request" = LocalProxy(partial(_lookup_req_object, "request"))  
              偏函数---》partial(_lookup_req_object, "request") 即执行 _lookup_req_object('request'), name='request'
def _lookup_req_object(name):
    top = _request_ctx_stack.top
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    return getattr(top, name)
View Code
                  top = _request_ctx_stack.top ---> _request_ctx_stack = LocalStack() 
                     即执行 LocalStack().top --->return self._local.stack[-1] || self._local = Local(),即取Local对象中的stack[-1]的索引返回 ---> 即 top = Local().stack[-1] 即top = ctx对象
                      (---> 执行Local().__getattr__方法,top = Local().stack[-1])
    def __getattr__(self, name: str) -> t.Any:
        values = self._storage.get({})
        try:
            return values[name]
        except KeyError:
            raise AttributeError(name)
View Code
                  return getattr(top, name)    --->  return top.request || name=request ---> ctx.request (即第一步中封装的request对象)

              实例化---》request = LocalProxy(函数) ---〉 函数对应传递给Localproxy对象中的local参数
    def __init__(
        self,
        local: t.Union["Local", t.Callable[[], t.Any]],
        name: t.Optional[str] = None,
    ) -> None:
        object.__setattr__(self, "_LocalProxy__local", local)
        object.__setattr__(self, "_LocalProxy__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)

              

        print(request)执行对象的__str__方法---Localproxy的__str__






(旧版源码,_get_current_object--即会调用执行local这个函数参数----—???)


》〉》〉》〉》最终request=ctx.request. (即第一步中封装的request对象)
所以视图函数中的request 就是 一个包含了请求参数的Request对象





流程图




2.3 ctx.auto_pop(error)





posted on 2021-06-03 14:36  Karlie24  阅读(120)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3