1.关于local

python中有threading local处理方式,在多线程环境中将变量按照线程id区分

由于协程在Python web中广泛使用,所以threading local不再满足需要

local中优先使用greenlet协程,其次是线程id,如下所示:

try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident

另外local中定义了一个__release_local__函数,用于清除本协程(线程)下的所有数据:

    def __release_local__(self):
self.__storage__.pop(self.__ident_func__(), None)

2 localstack

localstack相当于在本协程(线程)中将数据以stack的形式存储

这是通过封装local来实现的

3 localproxy

如其名字所示,这是local的代理。

下面由flask中的context locals来分析

# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

首先是current_app,我们首先要知道_find_app长啥样:

def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app

ok,_app_ctx_stack,这个东西是一个localstack的对象。

localstack的构造函数里只干了一件事:

self._local = Local()

那 _app_ctx_stack.top是什么意思?其实就是取绑定在self._local的stack(一个list)的顶部值:

  @property
def top(self):
"""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
也就是说,我们传入localproxy的是一个callable的函数,当call的时候,返回当前线程中app stack里面顶部元素所绑定的的app
下面我们需要看localproxy的构造函数了:
    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)

ok,当我们使用self.__local的时候,实际上使用的是传入的callable object: _find_app

接着分析request:

partial(_lookup_req_object, 'request'),意味着当call _lookup_req_object的时候,'request'会作为第一个参数传入。

那call _lookup_req_object 的时候发生了什么?

def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)

ok,实际上返回当前线程中request stack里面顶部元素所绑定的的request的属性

session,g的分析与request同理,只不过前者是在request stack上,后者是在app stack上

ref: https://www.jianshu.com/p/3f38b777a621

werkzeug(flask)中的local,localstack,localproxy探究的更多相关文章

  1. Flask(3)- flask中的CBV、werkzeug+上下文初步解读、偏函数和线程安全

    一.flask中的CBV 对比django中的CBV,我们来看一下flask中的CBV怎么实现? from flask import Flask, render_template, url_for, ...

  2. Flask中全局变量的实现

    我们都知道在Flask中g,request,session和request是作为全局对象来提供信息的,既然是全局的又如何保持线程安全呢,接下来我们就看看flask是如何做到这点的.在源码中的ctx.p ...

  3. 深入flask中的request

    缘起 在使用flask的时候一直比较纳闷request是什么原理,他是如何保证多线程情况下对不同请求参数的隔离的. 准备知识 在讲request之前首先需要先理解一下werkzeug.local中的几 ...

  4. flask中的上下文_请求上下文和应用上下文

    前引 在了解flask上下文管理机制之前,先来一波必知必会的知识点. 面向对象双下方法 首先,先来聊一聊面向对象中的一些特殊的双下划线方法,比如__call__.__getattr__系列.__get ...

  5. Flask中current_app和g对象

      Flask零基础到项目实战(七)请求方法.g对象和钩子函数 一.get方法 二.post方法 post请求在模板中要注意几点: input标签中,要写name来标识这个value的key,方便后台 ...

  6. Flask中的请求上下文和应用上下文

    在Flask中处理请求时,应用会生成一个“请求上下文”对象.整个请求的处理过程,都会在这个上下文对象中进行.这保证了请求的处理过程不被干扰.处理请求的具体代码如下: def wsgi_app(self ...

  7. Flask中请求数据的优雅传递

    当一个请求到来时,浏览器会携带很多信息发送发送服务端.在Django中,每一个处理函数都要传入一个request的参数,该参数携带所有请求的信息,也就是服务端程序封装的environ(不明白该参数可以 ...

  8. Flask中的CBV和上下文初步解读

    一 . flask中的CBV 相对于Django中的CBV,让我们来看看flask中的CBV是如何实现的 ? from flask import Flask, render_template, url ...

  9. Flask补充--threading.local对象

    目录 Local 局部变量 全局变量 使用threading.local() 自定义threading.local 函数版 面向对象版 通过setattr和getattr实现 每个对象有自己的存储空间 ...

随机推荐

  1. nested exception is java.sql.SQLException: IO 错误

    1.错误描述 (mx.messaging.messages::ErrorMessage)#0 body = (null) clientId = "18CE3B03-9709-9DA8-763 ...

  2. 芝麻HTTP:PhantomJS的安装

    PhantomJS是一个无界面的.可脚本编程的WebKit浏览器引擎,它原生支持多种Web标准:DOM操作.CSS选择器.JSON.Canvas以及SVG. Selenium支持PhantomJS,这 ...

  3. Django学习-21-表关系参数

    一对多关系 ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要进行关联的表名 to_field=None, # 要关联的表中 ...

  4. jQuery.extend 函数使用详解

    JQuery的extend扩展方法:      Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,在此,我们一起去了解了解.      一.Jquery的扩展方 ...

  5. C#属性的使用--C#基础

    1.属性的作用:保护字段,对字段取值与赋值进行限定 2.属性的使用: _name(属性名)public [对应字段类型] 属性名Name{ get{return _name;} set{_name=v ...

  6. zk个人入门学习总结(1)

    ZooKeeper是一种分布式协调服务,用于管理大型主机.在分布式环境中协调和管理服务是一个复杂的过程.ZooKeeper通过其简单的架构和API解决了这个问题.ZooKeeper允许开发人员专注于核 ...

  7. 【BZOJ1934】善意的投票(网络流)

    [BZOJ1934]善意的投票(网络流) 题面 Description 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己 ...

  8. Poj2723:Get Luffy Out

    题意 给出 n 对钥匙,每对只能挑一把使用,每把只能用一次,当一对钥匙中的一把被使用后,另一把也就不能再用了:然后给出 m 道门,每个门都有两把钥匙可以打开,问最多能开几道门(按给出的顺序开). So ...

  9. 百度统计&友盟统计

    一.百度统计 登录百度站长统计账号-->管理 --->代码获取-->复制代码,如 <script> var _hmt = _hmt || []; (function() ...

  10. SQL Server将自己的查询结果作为待查询数据子列之一

    嵌套子查询是SQL语句中比较常用的一种查询方法,开发过程中遇到查询需要将自己的某列作为待查询的数据,在参考别人的SQL语句的写法终于实现了自己需要的功能. 查询语句如下: SELECT DISTINC ...