Werkzeug之Local源码解析

Werkzeug之Local源码解析

原博客地址

http://liuyajing.coding.me/blogs/python/2018/werkzeug-local/

一、引入

最近在阅读 Flask 的源码,遇到三个概念:Local 、 LocalStack 和 LocalProxy ,本文主要就针对 Local 概念及其源码进行原理剖析。

二、Local

Local 是一个类,源码位置:site-packages/werkzeug/local.py

在模块的开头,有以下代码:

# 由于每个线程都有自己的greenlet,我们可以将它们用作上下文的标识符。
# 如果greenlet不可用,我们将根据它的位置回退到当前的线程标识。
try:
    from greenlet import getcurrent as get_ident
except ImportError:
    try:
        from thread import get_ident
    except ImportError:
        from _thread import get_ident

1. 定义

class Local(object):
    # 定义此类允许绑定的属性名称 tuple
    __slots__ = ('__storage__', '__ident_func__')

2. init

def __init__(self):
    object.__setattr__(self, '__storage__', {})
    object.__setattr__(self, '__ident_func__', get_ident)
'''
调用object 的__setattr__ 方法设置类Local的两个属性值, 即:
self.__storage__ = {}, self.__ident__func__ = get_ident
'''

3. iter

def __iter__(self):
    return iter(self.__storage__.items())
'''
__iter__方法返回一个迭代器,说明Local实例是一个可迭代对象
'''

4. call

def __call__(self, proxy):
    """Create a proxy for a name."""
    return LocalProxy(self, proxy)
'''
在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象,那就可以像函数一样调用它。
'''

5. getattr

def __getattr__(self, name):
    try:
        return self.__storage__[self.__ident_func__()][name]
    except KeyError:
        raise AttributeError(name)
'''
如果 name 被访问,同时它不存在的时候,此方法被调用。
此方法实现了通过直接访问类属性的方式间接获取字典 self.__storage__[self.__ident_func__()]中key为name的值,而name并不属于类的属性,而此函数一定会被调用,很巧妙的        写法。
'''

6. setattr

def __setattr__(self, name, value):
    ident = self.__ident_func__()
    storage = self.__storage__
    try:
        storage[ident][name] = value
    except KeyError:
        storage[ident] = {name: value}
'''
如果要给name赋值,就调用这个方法。
此方法实现了通过直接给类属性赋值达到间接往字典self.__storage__[self.__ident_func__()]中插入{name: value}的目的。
'''

7. delattr

def __delattr__(self, name):
    try:
        del self.__storage__[self.__ident_func__()][name]
    except KeyError:
        raise AttributeError(name)

'''
如果要删除name,这个方法就被调用。
此方法实现了通过直接删除类属性达到间接从字典 self.__storage__[self.__ident_func__()]中删除key的目的。
'''

8. release_local

def __release_local__(self):
    self.__storage__.pop(self.__ident_func__(), None)
'''
此方法是为了删除字典self.__storage__中key为self.__ident_func__()及对应的value值。
'''

9. 总结

'''
- Local 类实际是对 dict __storage__ 的封装,而这个dict中 的 key 使用的就是get_indent 函数获取的 id (当有 greenlet时使用 greenlet id,没有则使用 thread id)
- dict __storage__ 中的 value 也是一个 dict,这个 dict 就是该 greenlet (或者thread) 对应的 local 存储空间
- 通过重新实现 __getattr__、__setattr__、__delattr__ 等方法,我们在 greenlet 或者 thread 中使用 Local 实例对象时,可以通过访问类属性的方式 (会自动获取greenlet
- id (或者 thread id)) ,访问到对应的 dict 存储空间中真正存储的对象。
- 这个技巧在实际编写线程安全或协程安全的代码时是非常有用的,即通过 greenlet id ( thread id ) 来分别存储数据。
- 当需要释放 greenlet ( 或 thread ) 对应的存储空间时,可以通过调用__release_local__() 函数来实现。
'''

原文地址:https://www.cnblogs.com/daviddd/p/11916986.html

时间: 2024-08-30 14:29:27

Werkzeug之Local源码解析的相关文章

Werkzeug之LocalStack源码解析

Werkzeug之LocalStack源码解析 原博文地址 http://liuyajing.coding.me/blogs/python/2018/werkzeug-localstack/ 一.引入 最近在阅读 Flask 的源码,遇到三个概念:Local . LocalStack 和 LocalProxy ,本文主要就针对 LocalStack 概念及其源码进行原理剖析. 二.原理 这个类类似于:class:Local,但是在 storage[ident] 中存放的是一个 key 为 sta

消息中间件 RocketMQ源码解析:事务消息

关注微信公众号:[芋艿的后端小屋]有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将得到认真回复.甚至不知道如何读源码也可以请教噢. 新的源码解析文章实时收到通知.每周更新一篇左右. 1. 概述 2. 事务消息发送 2.1 Producer 发送事务消息 2.2 Broker 处理结束事务请求 2.3 Broker 生成

Android 热修复Nuwa的原理及Gradle插件源码解析

现在,热修复的具体实现方案开源的也有很多,原理也大同小异,本篇文章以Nuwa为例,深入剖析. Nuwa的github地址 https://github.com/jasonross/Nuwa 以及用于hotpatch生成的gradle插件地址 https://github.com/jasonross/NuwaGradle 而Nuwa的具体实现是根据QQ空间的热修复方案来实现的.安卓App热补丁动态修复技术介绍.在阅读本篇文章之前,请先阅读该文章. 从QQ空间终端开发团队的文章中可以总结出要进行热更

Fresco源码解析 - 创建一个ImagePipeline(一)

在Fresco源码解析 - 初始化过程分析章节中,我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipelineFactory.initialize(context);会创建一个所有参数都使用默认值的ImagePipelineConfig来初始化ImagePipeline. ImagePipelineFactory.initialize(imagePipelineConfig)会首先用 imagePipelin

Android xUtils3源码解析之图片模块

初始化 x.Ext.init(this); public static void init(Application app) { TaskControllerImpl.registerInstance(); if (Ext.app == null) { Ext.app = app; } } public final class TaskControllerImpl implements TaskController { public static void registerInstance()

【Spring源码分析】.properties文件读取及占位符${...}替换源码解析

前言 我们在开发中常遇到一种场景,Bean里面有一些参数是比较固定的,这种时候通常会采用配置的方式,将这些参数配置在.properties文件中,然后在Bean实例化的时候通过Spring将这些.properties文件中配置的参数使用占位符"${}"替换的方式读入并设置到Bean的相应参数中. 这种做法最典型的就是JDBC的配置,本文就来研究一下.properties文件读取及占位符"${}"替换的源码,首先从代码入手,定义一个DataSource,模拟一下JDB

nginx upstream使用及源码解析

nginx upstream机制使得nginx可以成为一个反向代理服务器,nginx一方面从下游客户端接收http请求,处理请求,并根据请求发送tcp报文到上游服务器,根据上游服务器的返回报文,来向下游客户端发送请求响应报文. upstream机制也提供了负载分担的功能,可以将请求负载分担到集群服务器的某个服务器上面. 2.1upstream的流程介绍 1分析客户端请求报文,构建发往上游服务器的请求报文. 2调用ngx_http_upstream_init开始与上游服务器建立tcp连接. 3发送

使用SBT开发Akka第一个案例源码解析MapActor、ReduceActor、AggregateActor

学习了使用SBT开发Akka第一个案例源码解析MapActor.ReduceActor.AggregateActor,应用MapActor对单词计数,发信息给ReduceActor,对信息进行local级的汇总,然后交给AggregateActor. 案例如下: class MapActor(reduceActor: ActorRef) extend Actor{ val STOP_WORDS_LIST=List("a","is") deg receive: Rec

android源码解析--Handler

转载自:http://blog.csdn.net/lilu_leo/article/details/8143205 开始,先看下android官方对于Handler的解释: [java] view plaincopy /** * A Handler allows you to send and process {@link Message} and Runnable * objects associated with a thread's {@link MessageQueue}.  Each