werkzeug(flask)中的local,localstack,localproxy探究

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上

原文地址:https://www.cnblogs.com/geeklove01/p/8542868.html

时间: 2024-08-29 21:38:46

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

Flask中全局变量的实现

我们都知道在Flask中g,request,session和request是作为全局对象来提供信息的,既然是全局的又如何保持线程安全呢,接下来我们就看看flask是如何做到这点的.在源码中的ctx.py中有AppContext和RequestContext两个类,他们分别管理应用上下文和请求上下文.两者的实现也差不多,这里我们看看AppContext的实现 class AppContext(object): """The application context binds a

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

本文章粘贴自 https://blog.tonyseek.com/post/the-context-mechanism-of-flask/ 用过 Flask 做 Web 开发的同学应该不会不记得 App Context 和 Request Context 这两个名字--这两个 Context 算是 Flask 中比较特色的设计.[1] 从一个 Flask App 读入配置并启动开始,就进入了 App Context,在其中我们可以访问配置文件.打开资源文件.通过路由规则反向构造 URL.[2] 

Flask中处理依赖的技巧

Flask应用中通常会用工厂模式 来创建应用对象,这样方便配置和测试.现在我们就用实例来学习Flask的处理依赖 应用代码 # app/__init__.pyfrom flask import Flaskfrom flask_xxxext import Xxxfrom flask_yyyext import Yyy# ... 一些flask拓展xx = Xxx()yy = Yyy() def create_app(config=None): app = Flask(__name__) xx.in

整合Flask中的目录结构

一.SQLAlchemy-Utils 由于sqlalchemy中没有提供choice方法,所以借助SQLAlchemy-Utils组件提供的choice方法 import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Text, ForeignK

用flask开发个人博客(4)—— flask中4种全局变量

https://blog.csdn.net/hyman_c/article/details/53512109 一  current_app current_app代表当前的flask程序实例,使用时需要flask的程序上下文激活,我们以本专栏第一篇文章中写的test.py为例介绍下它的用法: 1.1 激活程序上下文 [python] view plain copy >>> from test import app >>> from flask import curren

flask框架----整合Flask中的目录结构

一.SQLAlchemy-Utils 由于sqlalchemy中没有提供choice方法,所以借助SQLAlchemy-Utils组件提供的choice方法 import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Text, ForeignK

Flask中'endpoint'(端点)的理解

Flask路由是如何工作的 整个flask框架(及以Werkzeug类库为基础构建的应用)的程序理念是把URL地址映射到你想要运行的业务逻辑上(最典型的就是视图函数),例如: @app.route('/greeting/<name>') def give_greeting(name): return 'Hello, {0}!'.format(name) 1 2 3 注意,add_url_rule函数实现了同样的目的,只不过没有使用装饰器,因此,下面的程序是等价的: # 抬头没有使用路由装饰器,

Flask学习【第11篇】:整合Flask中的目录结构

SQLAlchemy-Utils 由于sqlalchemy中没有提供choice方法,所以借助SQLAlchemy-Utils组件提供的choice方法 import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Text, ForeignKey

在flask中使用celery的实践

前言 在web开发中我们经常会遇到一些耗时的操作,比如发送邮件/短信,执行各种任务等等,这时我们会采取异步的方式去执行这些任务,而celery就是这样的一个异步的分布式任务处理框架,官方文档 今天,我们的主题是celery如何与flask一起工作,我们都知道,flask是一个非常小巧的web框架,有许许多多的扩展,celery也不例外,我们先看下目前常用的几个flask-celery的扩展: Flask-Celery: celery作者本人开发的,其实不算扩展,功能就是安装celery及其相关组