zoukankan      html  css  js  c++  java
  • Flask 进阶session和上下文管理解析

    session的源码流程

     

     将session放置在redis中

    安装

    pip install flask-session

    使用

    import redis
    from flask import Flask,request,session
    from flask.sessions import SecureCookieSessionInterface
    from flask_session import Session
    
    app = Flask(__name__)
    app.config['SESSION_TYPE'] = 'redis'
    app.config['SESSION_REDIS'] = redis.Redis(host='140.143.227.206',port=6379,password='1234')
    Session(app)
    
    @app.route('/login')
    def login():
        session['user'] = 'alex'
        return 'asdfasfd'
    
    @app.route('/home')
    def index():
        print(session.get('user'))
    
        return '...'
    
    
    if __name__ == '__main__':
        app.run()

    上下文管理基础

    上下文管理之基础threading.local

     1.threading.local 

    • 实例化一个local对象
    • obj.xxxx=i会触发__setattr__ 设置值
    • obj.xxxx的会触发__getattr__取值
    • local能为每一个线程开辟一个新的空间,让每个线程的资源相互不干扰
    import threading,time
    from threading import local
    obj=local()
    def task(i):
        obj.xxxxx = i
        time.sleep(2)
        print(obj.xxxxx,i)
    
    for i in range(0,10):
        t=threading.Thread(target=task,args=(i,))
        t.start()

     2.用字典替换local

    import threading,time
    from threading import local
    
    obj=local()
    DIC={}
    def task(i):
        ident = threading.get_ident()
        if ident in DIC:
            DIC[ident]['xxxx']=i
        else:
            DIC[ident]={'xxxx':i}
        time.sleep(2)
        print(DIC[ident]['xxxx'],i,ident)
    for i in range(0,10):
        t=threading.Thread(target=task,args=(i,))
        t.start()
    • ident = threading.get_ident() 获取线程的唯一标识

    • 将所有的数据根据线程唯一标示为key存放到字典里,那么该方法也可以避免线程资源冲突...因为DIC是一个全部变量字典

    3. 重写local支持协程

    import threading,time,greenlet
    try:
        get_ident=greenlet.getcurrent
    except Exception as e:
        get_ident=threading.get_ident
    class Local(object):
        DIC={}
        def __getattr__(self, item):
            ident = get_ident()
            print(ident)
            if ident in self.DIC:
                return self.DIC[ident].get(item)
            return None
        def __setattr__(self, key, value):
            ident= get_ident()
            if ident in self.DIC:
                self.DIC[ident][key]=value
            else:
                self.DIC[ident]={key:value}
    obj=Local()
    def task(i):
        obj.ha=i
        time.sleep(2)
        print(obj.ha)
    for i in range(0,10):
        t= threading.Thread(target=task,args=(i,))
        t.start()

    上下文管进阶理解

     1.偏函数

    # by luffycity.com
    import functools
    def index(a1,a2):
        return a1 + a2
    # 原来的调用方式
    # ret = index(1,23)
    # print(ret)
    # 偏函数,帮助开发者自动传递参数
    new_func = functools.partial(index,666)
    ret = new_func(1)
    print(ret)

    2.执行父类方法

    class Base(object):
        def func(self):
            print('Base.func')
    class Foo(Base):
        def func(self):
            # 方式一:根据mro的顺序执行方法
            # super(Foo,self).func()
            # 方式二:主动执行Base类的方法
            # Base.func(self)
    
            print('Foo.func')
    obj = Foo()
    obj.func()
    # print(Foo.__mro__)
     

    3.object.__setattr__

    class Foo(object):
        def __init__(self):
            # self.storage = {}
            # 在父类的setattr设置storage为空列表
            object.__setattr__(self,'storage',{})
        def __getattr__(self, item):
            print item
    
        def __setattr__(self, key, value):
            print(key,value,self.storage)
    
    obj = Foo()
    obj.xx = 123
    • obj=Foo() 实例化对象会执行,__new__......再执行__init__方法加上object.__setattr__会执行object类的方法设置值
    • obj.xx=123设置值会执行该类的__setattr__

    4.Flask  Local源码

    • local是用来给每个线程或者协程开辟一个空间
    try:
        from greenlet import getcurrent as get_ident
    except:
        from threading import get_ident
    class Local(object):
        __slots__ = ('__storage__', '__ident_func__')
    
        def __init__(self):
            # __storage__ = {1231:{'stack':[]}}
            object.__setattr__(self, '__storage__', {})
            object.__setattr__(self, '__ident_func__', get_ident)
    
        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)

    5.LocalStack源码

    • localstack 维护local的列表,维护成一个栈
    class LocalStack(object):
        def __init__(self):
            self._local = Local()
    
        def push(self,value):
            rv = getattr(self._local, 'stack', None) # self._local.stack =>local.getattr
            if rv is None:
                self._local.stack = rv = [] #  self._local.stack =>local.setattr
            rv.append(value) # self._local.stack.append(666)
            return rv
    
    
        def pop(self):
            """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:
                return stack[-1]
            else:
                return stack.pop()
    
        def top(self):
            try:
                return self._local.stack[-1]
            except (AttributeError, IndexError):
                return None

    源码入口

    app.__call__
    app.wsgi_app

    上下文管理request简易流程图

    上下文管理request,session流程

    • -请求到来之后会触发__call__方法,由__call__方法再次调用wsgi__app方法
    • -在wsgi_app方法中:
    • -首先将请求相关+空session封装到一个RequestContext对象中即:ctx
    • -将ctx交给LocalStack对象,再由LocalStack将ctx添加到local中,Local结构:
    • __storage__={
    • 线/协程的唯一标识:{stack:[ctx,]}
    • -根据请求中的cookie中提取铭文sessionid对应的值,对cookie进行加密+反序列化
    • ->视图函数
    • -把session中的数据再次加密序列化写入到cookie中.
    • -将ctx删除
    • -结果返回给用户浏览器
    • -断开socket连接.
      #LocalStack是全局的 单例模式
      _request_ctx_stack = LocalStack()
      _app_ctx_stack = LocalStack()
      request = LocalProxy(partial(_lookup_req_object, 'request'))
      session = LocalProxy(partial(_lookup_req_object, 'session'))

    上下文管理最终流程图

  • 相关阅读:
    5分钟机器学习
    快速排序
    数据预处理 总结
    正则化 / 特征选择
    424. 替换后的最长重复字符 sliding window中的注意点
    自然语言处理算法精讲P3
    76. 最小覆盖子串
    3.无重复字符的最长子串 —— sliding window
    自然语言处理算法精讲 P1
    18.四数之和
  • 原文地址:https://www.cnblogs.com/chenxuming/p/9426089.html
Copyright © 2011-2022 走看看