0


(十九)Flask之自定义实现local对象功能

第一版:基于函数实现local对象功能

紧接上文,最最直白的实现方式:

import time
from threading import get_ident, Thread

storage ={}defset(k, v):
    ident = get_ident()if ident in storage:
        storage[ident][k]= v
    else:
        storage[ident]={k: v}defget(k):
    ident = get_ident()return storage[ident][k]deftask(arg):set('val', arg)
    time.sleep(2)
    v = get('val')print(v)for i inrange(10):
    t = Thread(target=task, args=(i,))
    t.start()

已经可以实现local对象的功能,但是这样的话使用很不方便!

在这里插入图片描述

第二版:基于面向对象思想实现local对象功能

(1)2.1版本:

import time
from threading import get_ident, Thread

classLocal(object):
    storage ={}defset(self, k, v):
        ident = get_ident()if ident in Local.storage:
            Local.storage[ident][k]= v
        else:
            Local.storage[ident]={k: v}defget(self, k):
        ident = get_ident()return Local.storage[ident][k]if __name__ =='__main__':
    obj = Local()deftask(arg):
        obj.set('val', arg)
        time.sleep(2)
        v = obj.get('val')print(v)for i inrange(10):
        t = Thread(target=task, args=(i,))
        t.start()

(2)2.2版本:

  • 实现local对象的通过.value进行赋值操作:

在这里插入图片描述

import time
from threading import get_ident, Thread

classLocal(object):
    storage ={}def__setattr__(self, k, v):
        ident = get_ident()if ident in Local.storage:
            Local.storage[ident][k]= v
        else:
            Local.storage[ident]={k: v}def__getattr__(self, k):
        ident = get_ident()return Local.storage[ident][k]if __name__ =='__main__':
    obj = Local()deftask(arg):
        obj.val = arg
        time.sleep(2)
        v = obj.val
        print(v)for i inrange(10):
        t = Thread(target=task, args=(i,))
        t.start()

(3)2.3版本:

上述代码存在一个很严重的问题:由于storage是定义为Local类的一个类属性,所以不管创建几个Local()对象,用的都是同一个storage来存!

在这里插入图片描述

优化点就是:让代码变得可以放同一个storage/不同storage!

如下将storage变为实例属性即可(想放一个storage里就实例化一个Local对象,想放不同storage里就分别实例化对应Local对象即可):

在这里插入图片描述

但是上面这会报错,定位到实例化Local对象时报的错,如下:

在这里插入图片描述
在这里插入图片描述

问题分析:

  • 实例化后会触发init方法,在里面有个self.storage={},就会触发setattr方法,里面判断走else,所以又触发setattr

问题解决:

  • 因为Local继承了类object,所以可以使用基类object的setattr来触发父类的setattr来设置storage,这样就在设置实例属性storage的时候绕过了setattr的自定义实现:在这里插入图片描述

分析:

  • 上述2.3版本已经实现了threading.local。但是为啥已经有现成的了,我们不直接用,还要自行实现呢?
  • 答案很简单,因为threading.local的功能不够用!

比如我们现在要实现为每个协程创建一份空间。上述2.3版本代码只需要更改一处就可以了(下述代码段第三行)!

【greenlet.getcurrent就是获取当前协程的唯一标识】

import time
from threading import Thread
from greenlet import getcurrent as get_ident

classLocal(object):def__init__(self):# self.storage = {}object.__setattr__(self,'storage',{})def__setattr__(self, k, v):
        ident = get_ident()if ident in self.storage:
            self.storage[ident][k]= v
        else:
            self.storage[ident]={k: v}def__getattr__(self, k):
        ident = get_ident()return self.storage[ident][k]if __name__ =='__main__':
    obj = Local()deftask(arg):
        obj.val = arg
        time.sleep(2)
        v = obj.val
        print(v)for i inrange(10):
        t = Thread(target=task, args=(i,))
        t.start()

到现在,我们已经非常牛逼了,因为这就是flask里的源码:

from flask importglobals

在这里插入图片描述

在这里插入图片描述

classLocal(object):
    __slots__ =("__storage__","__ident_func__")def__init__(self):object.__setattr__(self,"__storage__",{})object.__setattr__(self,"__ident_func__", get_ident)def__iter__(self):returniter(self.__storage__.items())def__call__(self, proxy):"""Create a proxy for a name."""return LocalProxy(self, proxy)def__release_local__(self):
        self.__storage__.pop(self.__ident_func__(),None)def__getattr__(self, name):try:return self.__storage__[self.__ident_func__()][name]except KeyError:raise AttributeError(name)def__setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name]= value
        except KeyError:
            storage[ident]={name: value}def__delattr__(self, name):try:del self.__storage__[self.__ident_func__()][name]except KeyError:raise AttributeError(name)

会发现这个源码跟上述2.3版本代码一样哦!!!

标签: flask python 后端

本文转载自: https://blog.csdn.net/qq_44907926/article/details/135375054
版权归原作者 孤寒者 所有, 如有侵权,请联系我们删除。

“(十九)Flask之自定义实现local对象功能”的评论:

还没有评论