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对象栈
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中存储的数据进行销毁.