# Flask 源码剖析

Flask 源码剖析

偏函数 partial

  • 对普通函数进行封装, 主要功能是把一个函数的部分参数给固定住
from functools import partial

def add(a, b):
    return a*b

d1 = add(4,5)
print(d1) # 20

# 偏函数
new_d1 = partial(add,4)
print(new_d1)
# functools.partial(<function add at 0x0000027535702EA0>, 4) 
# 将参数固定

print(new_d1(5)) # 20

Local对象维护栈

  • 根据线程id/协程id , 维护一个存储空间 . 以字典形式
  • 结构: {"线程/协程id":{"_storage":[ctx(request/session)]}}
try:
    from greenlet import getcurrent as _get_ident
except ImportError:
    from threading import get_ident as _get_ident
    
# Local  
# - 主要目的:开辟空间 

class Local:
    __slots__ = ("_storage",)

    def __init__(self) -> None:
        # 设置 _storage
        object.__setattr__(self, "_storage", ContextVar("local_storage"))

    def __iter__(self) -> t.Iterator[t.Tuple[int, t.Any]]:
        return iter(self._storage.get({}).items())

    def __call__(self, proxy: str) -> "LocalProxy":
        """Create a proxy for a name."""
        return LocalProxy(self, proxy)

    def __release_local__(self) -> None:
        # 释放 local 对象资源
        __release_local__(self._storage)

    def __getattr__(self, name: str) -> t.Any:
        # 获取数据
        values = self._storage.get({})
        try:
            return values[name]
        except KeyError:
            raise AttributeError(name) from None

    def __setattr__(self, name: str, value: t.Any) -> None:
        # 增加数据
        values = self._storage.get({}).copy()
        values[name] = value
        self._storage.set(values)

    def __delattr__(self, name: str) -> None:
        # 移除数据
        values = self._storage.get({}).copy()
        try:
            del values[name]
            self._storage.set(values)
        except KeyError:
            raise AttributeError(name) from None
    

LocalStack对象栈

  • Local中的列表维护成栈
class LocalStack:
  
    def __init__(self) -> None:
        # 封装 Local类 为 属性对象
        self._local = Local()

    def __release_local__(self) -> None:
        # 释放 local空间 资源
        self._local.__release_local__()

    def __call__(self) -> "LocalProxy":
        def _lookup() -> t.Any:
            rv = self.top
            if rv is None:
                raise RuntimeError("object unbound")
            return rv

        return LocalProxy(_lookup)

    def push(self, obj: t.Any) -> t.List[t.Any]:
        """Pushes a new item to the stack"""
        # 将新ctx/app_ctx对象 , 存堆栈中
        rv = getattr(self._local, "stack", []).copy()
        rv.append(obj)
        self._local.stack = rv
        return rv

    def pop(self) -> t.Any:
        """Removes the topmost item from the stack, will return the
        old value or `None` if the stack was already empty.
        """
       # 将新ctx/app_ctx对象从堆栈中移除,当 Local中没有对象时,释放资源
        stack = getattr(self._local, "stack", None)
        if stack is None:
            return None
        elif len(stack) == 1:
            release_local(self._local)
            return stack[-1]
        else:
            return stack.pop()

    @property
    def top(self) -> t.Any:
        """The topmost item on the stack.  If the stack is empty,
        `None` is returned.
        """
        # 获取 栈顶对象
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None

RequestContext , AppContext对象

  • RequestContext 请求上下文对象
    • 接收到请求后,第一步创建请求上下文 RequestContext 对象
    • request 存储着几乎所有的请求数据信息, 当请求处理完成后被销毁
    • session 字典容器,当请求处理完成后被销毁
# 
class RequestContext(object):
    def __init__(self, app, environ, request=None):
        self.app = app
        if request is None:
            request = app.request_class(environ) # 使用app的Request对象创建一个实例
        self.request = request # 请求上下文的request
        self.url_adapter = app.create_url_adapter(self.request)
        self.flashes = None
        self.session = None # 请求上下文的session
        self._implicit_app_ctx_stack = [] # 请求上下文的应用上下文临时存放点
        self.preserved = False
        self._preserved_exc = None
        self._after_request_functions = []
        self.match_request() # 提取请求的路由创建request对象的Rule对象

        
  • AppContext 应用上下文对象
    • current_app 存在于应用上下文活跃期间,会在请求处理完成后,随着应用上下文销毁而销毁
    • g 请求期间管理资源 , {}
class AppContext(object):
    def __init__(self, app):
        self.app = app
        self.url_adapter = app.create_url_adapter(None)
        self.g = app.app_ctx_globals_class() # app的全局变量

flask上下文管理机制

1. 当用户请求到来之后,flask内部会创建两个对象:
	ctx = ReqeustContext(),内部封装request/sesion
	app_ctx = AppContext(),内部封装app/g
    
2. 然后会将此对象通过各自的LocalStack对象:
	_request_ctx_stack = LocalStack()
	_app_ctx_stack = LocalStack()
	将各自的对象添加到local中.

3. 
 Local是一个特殊结构,他可以为每个线程(协程)维护一个空间进行存取数据. 
 LocalStack的作用是将Local中维护成一个栈.

storage结构:
	storage = {
        1212:{stack:[ctx,]}
	}
	
	storage = {
        1212:{stack:[app_ctx,]}
	}
	
	
4. 视图函数如果想要获取:request/session/app/g,只需要导入即可,
   导入的本质是去各自storage中获取各自的对象,并调用封装其内部:request/session/app/g. (获取栈顶的数据top)

5. 请求处理完毕,将各自storage中存储的数据进行销毁. 
posted @   染指未来  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示