百木园-与人分享,
就是让自己快乐。

flask上下文

flask上下文预备知识点

面向对象attr

class Foo(object):
def __init__(self):
# self.storage = {}
object.__setattr__(self, \'storage\', {})

def __setattr__(self, key, value):
self.storage[key] = value

def __getattr__(self, item):
return self.storage.get(item)

cls = Foo() #创建对象
cls.x1 = 123 #调用setattr方法
cls.x1 #调用getattr方法

线程的唯一标识

import threading
from threading import get_ident

def task():
ident = get_ident() # 线程的唯一标识 线程id
print(ident)

for i in range(10):
t = threading.Thread(target=task)
t.start()

local对象与flask的上下文

每一个request都是一个线程,每个线程有自己唯一的线程ID,利用这个线程ID作为标识,来存储request对象。
这样的话就可以为每个线程开辟独立的空间互不影响。

自己实现threading.local

点击查看代码
import threading
from threading import get_ident

\'\'\'
storage = {
1111:{x1:1}
1112:{x1:2}
1113:{x1:3}
1114:{x1:4}
}
\'\'\'

class Local(object):
def __init__(self):
object.__setattr__(self, \'storage\', {}) # 相当于self.storage = {}

def __setattr__(self, key, value):
ident = get_ident()
if ident in self.storage: # 如果ident在字典里面就直接修改就行了
self.storage[ident][key] = value
else: # 不在字典里面就添加
self.storage[ident] = {key:value}

def __getattr__(self,item):
ident = get_ident()
if ident not in self.storage:
return
return self.storage[ident].get(item)

local = Local()

def task(num):
local.x1 = num
print(local.x1)

if __name__ == \'__main__\':
for i in range(5):
t = threading.Thread(target=task, args=(i,))
t.start()

加强版threading.local

点击查看代码
import threading
from threading import get_ident

\'\'\'
storage = {
1111:{x1:[1]}
1112:{x1:[]}
1113:{x1:[]}
1114:{x1:[]}
}
维护成一个栈
\'\'\'

class Local(object):
def __init__(self):
object.__setattr__(self, \'storage\', {}) # 相当于self.storage = {}

def __setattr__(self, key, value):
ident = get_ident()
if ident in self.storage: # 如果ident在字典里面就直接修改就行了
self.storage[ident][key].append(value)
else: # 不在字典里面就添加
self.storage[ident] = {key:[value]}

def __getattr__(self,item):
ident = get_ident()
if ident not in self.storage:
return
return self.storage[ident][item][-1]

local = Local()

def task(num):
local.x1 = num
print(local.x1)

if __name__ == \'__main__\':
for i in range(5):
t = threading.Thread(target=task, args=(i,))
t.start()

flask源码的local对象和localstack对象

flask的locak对象

点击查看代码
class Local:
__slots__ = (\"_storage\",)

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

@property
def __storage__(self) -> t.Dict[str, t.Any]:
warnings.warn(
\"\'__storage__\' is deprecated and will be removed in Werkzeug 2.1.\",
DeprecationWarning,
stacklevel=2,
)
return self._storage.get({}) # type: ignore

@property
def __ident_func__(self) -> t.Callable[[], int]:
warnings.warn(
\"\'__ident_func__\' is deprecated and will be removed in\"
\" Werkzeug 2.1. It should not be used in Python 3.7+.\",
DeprecationWarning,
stacklevel=2,
)
return _get_ident # type: ignore

@__ident_func__.setter
def __ident_func__(self, func: t.Callable[[], int]) -> None:
warnings.warn(
\"\'__ident_func__\' is deprecated and will be removed in\"
\" Werkzeug 2.1. Setting it no longer has any effect.\",
DeprecationWarning,
stacklevel=2,
)

def __release_local__(self) -> None:
__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

flask的localstack对象

点击查看代码
class LocalStack:

def __init__(self) -> None:
self._local = Local()

def __release_local__(self) -> None:
self._local.__release_local__()

@property
def __ident_func__(self) -> t.Callable[[], int]:
return self._local.__ident_func__

@__ident_func__.setter
def __ident_func__(self, value: t.Callable[[], int]) -> None:
object.__setattr__(self._local, \"__ident_func__\", value)

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\"\"\"
rv = getattr(self._local, \"stack\", []).copy()
rv.append(obj)
self._local.stack = rv
return rv # type: ignore

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.
\"\"\"
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

# 总结

在flask中有个local类,他和threading.local的功能一样,为每个线程开辟空间来存储数据,他们两个的内部实现机制一样,内部维护一个字典,以线程(协程)ID为key,进行数据隔离如:

__storage__ = {
1111:{\'k1\':123}
}
obj = local()
obj.k1 = 123

在flask中还有localstack的类,他内部会依赖local对象,local对象负责存储数据,localstack对象用于将local中的值维护成一个栈。

__storage__ = {
1112:{\'stack\':[k1,]}
}
obj = LocalStack()
obj.push(\'k1\')
obj.pop()
obj.top

flask源码中一共有两个localstack对象

context locals

__storage__ = {
\'1111\':{\'stack\':[\'RequestContext(request, session)\',]},
\'1112\':{\'stack\':[\'RequestContext(request, session)\',]}
}

__storage__ = {
\'1111\':{\'stack\':[\'AppContext(app, g)\',]},
\'1112\':{\'stack\':[\'AppContext(app, g)\',]}
}

_request_ctx_stack = LocalStack() # 请求上下文
_app_ctx_stack = LocalStack() # 应用上下文

来源:https://www.cnblogs.com/libonizhenshuai/p/15551971.html
图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » flask上下文

相关推荐

  • 暂无文章