Flask 单例模式 session

一、单例模式

单例模式分为四种:基于文件的单例模式,基于类方法的单例模式,基于__new__的单例模式,基于metaclass的单例模式

1. 基于类方法的单例模式

- 不支持多线程模式

import threadingclass Singleton(object):def __init__(self):passimport timetime.sleep(1)@classmethoddef instance(cls,*args,**kwargs):if not hasattr(Singleton,'_instance'):Singleton._instance = Singleton(*args,**kwargs)return Singleton._instancedef task(arg):obj = Singleton.instance()print(obj)
for i in range(10):t = threading.Thread(target=task,args=[i,])t.start()
View Code

- 支持多线程模式,加锁(线程锁),保证线程安全

import time
import threading
class Singleton(object):_instance_lock = threading.Lock()       # 线程锁def __init__(self):time.sleep(1)@classmethoddef instance(cls, *args, **kwargs):if not hasattr(Singleton, "_instance"):         # 当有了_instance时,则直接返回,不用加锁。with Singleton._instance_lock:              # 当一个线程进来就会加锁,只有该线程执行完毕,其他线程等待if not hasattr(Singleton, "_instance"):Singleton._instance = Singleton(*args, **kwargs)return Singleton._instancedef task(arg):obj = Singleton.instance()print(obj)
for i in range(10):t = threading.Thread(target=task,args=[i,])t.start()
# 之后的使用不用加锁,都直接使用_instance
time.sleep(20)
obj = Singleton.instance()
print('#',obj)
View Code

 2. 基于__new__的单例模式

类单例模式需要,调用类方法,实例化时会先调用__new__

import time
import threadingclass Singleton(object):_instance_lock = threading.Lock()def __init__(self):# print('init',self)passdef __new__(cls, *args, **kwargs):if not hasattr(Singleton,'_instance'):with Singleton._instance_lock:if not hasattr(Singleton,'_instance'):Singleton._instance = object.__new__(cls,*args,**kwargs)return Singleton._instanceobj1 = Singleton()
obj2 = Singleton()
print(obj1)
print(obj2)
View Code

3. 基于metaclass方法实现的单例模式

对象是类创建,创建对象的时候类的__init__方法自动执行,对象()执行类的 __call__ 方法
类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)

- metaclass原理

# 继承type,模仿type的功能
class SingletonType(type):def __init__(self,*args,**kwargs):super(SingletonType,self).__init__(*args,**kwargs)def __call__(cls, *args, **kwargs):obj = cls.__new__(cls,*args,**kwargs)   # 1.1创建对象cls.__init__(obj,*args,**kwargs)        # 1.2初始化对象return obj# 第0步:将代码加载到内存中,编译类,执行type的__init__方法(类是type的对象)
class Foo(metaclass=SingletonType): #   指定metaclassdef __init__(self,name):self.name = namedef __new__(cls, *args, **kwargs):return object.__new__(cls,*args,**kwargs)# 第一步:执行type的__call__方法(类=type的对象)
#       1.1 调用Foo类(type的对象)的__new__方法,用于创建对象。
#       1.2 调用Foo类(type的对象)的__init__方法,用于对象初始化。
obj = Foo()# 第二步:执行Foo的__call__方法
obj()
View Code

- metaclass实现单例模式

import threading
class SingletonType(type):_instance_lock = threading.Lock()def __call__(cls, *args, **kwargs):if not hasattr(cls,'_instance'):with SingletonType._instance_lock:if not hasattr(cls,'_instance'):cls._instance = super(SingletonType,cls).__call__(*args,**kwargs)return cls._instance# 如需单例模式加上metaclass=SingletonType即可
class Foo(metaclass=SingletonType):def __init__(self,name):self.name = nameobj1 = Foo('name')
obj2 = Foo('name')
print(obj1)
print(obj2)
View Code

 4 .单例模式数据库连接池应用

# pool.py
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnectionclass SingletonDBPool(object):_instance_lock = threading.Lock()def __init__(self):# print('init',self)
self.pool = PooledDB(creator=pymysql,  # 使用链接数据库的模块maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5,  # 链接池中最多闲置的链接,0和None不限制maxshared=3,# 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]ping=0,# ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = alwayshost='127.0.0.1',port=3306,user='root',password='123456',database='flask_test',charset='utf8')def __new__(cls, *args, **kwargs):if not hasattr(SingletonDBPool,'_instance'):with SingletonDBPool._instance_lock:if not hasattr(SingletonDBPool,'_instance'):SingletonDBPool._instance = object.__new__(cls,*args,**kwargs)return SingletonDBPool._instancedef connect(self):return self.pool.connection()# app.py
from pool import SingletonDBPooldef run():pool = SingletonDBPoolconn = pool.connect()# 数据库连接con.close()    # 并没有真正断开连接if __name__ == '__main__':run()
View Code

 

二、session

1. 源码解析

# 1. 执行Flask类的__call__
class RequestContext(object):def __init__(self,environ):self.environ = environdef push(self):# 3# 请求相关数据,加到local中: stack.push...
        _request_ctx_stack.push(self)# 获取cookie中的随机字符串,检验是否有,没有就生成# 根据随机字符串,获取服务端保存的session的# {#     'xxxxxxx': {...}#     'xxxxxxx': {...}# }# 新用户: {}# 老用户:{user:'xxx'}self.session = self.app.open_session(self.request)if self.session is None:self.session = self.app.make_null_session()class Flask:def process_response(self, response):# 8# 执行 after_request装饰器for handler in funcs:response = handler(response)# 将内存中的session持久化到:数据库、....if not self.session_interface.is_null_session(ctx.session):self.save_session(ctx.session, response)return responsedef finalize_request(self, rv, from_error_handler=False):# 7response = self.make_response(rv)try:response = self.process_response(response)request_finished.send(self, response=response)except Exception:if not from_error_handler:raiseself.logger.exception('Request finalizing failed with an ''error while handling an error')return responsedef full_dispatch_request(self):# 5# 触发只执行一次的装饰器函数,@before_first_request
        self.try_trigger_before_first_request_functions()try:# 触发Flask的信号,没用: pip3 install blinker
            request_started.send(self)# 执行特殊装饰器:before_request# 如果没有返回值,rv=None;有返回值 “嘻嘻嘻”rv = self.preprocess_request()if rv is None:# 触发执行视图函数rv = self.dispatch_request()except Exception as e:rv = self.handle_user_exception(e)# 6 对返回值进行封装return self.finalize_request(rv)def wsgi_app(self, environ, start_response):# 处理request,将请求添加到local中ctx = self.request_context(environ)# 2.处理request和session
        ctx.push()error = Nonetry:try:# 4 执行视图函数response = self.full_dispatch_request()except Exception as e:error = eresponse = self.handle_exception(e)except:error = sys.exc_info()[1]raisereturn response(environ, start_response)finally:if self.should_ignore_error(error):error = None# 9
            ctx.auto_pop(error)def __call__(self, environ, start_response):"""Shortcut for :attr:`wsgi_app`."""# 1.xxxreturn self.wsgi_app(environ, start_response)
View Code

 

2. 自定义session

from flask import Flask,request,session
app = Flask(__name__)
app.secret_key = 'sdfsdfsd'
from flask.sessions import SessionInterface,SessionMixin
import uuid
import json
from flask.sessions import SessionInterface
from flask.sessions import SessionMixin
from itsdangerous import Signer, BadSignature, want_bytesclass MySession(dict, SessionMixin):def __init__(self, initial=None, sid=None):self.sid = sidself.initial = initialsuper(MySession, self).__init__(initial or ())def __setitem__(self, key, value):super(MySession, self).__setitem__(key, value)def __getitem__(self, item):return super(MySession, self).__getitem__(item)def __delitem__(self, key):super(MySession, self).__delitem__(key)class MySessionInterface(SessionInterface):session_class = MySessioncontainer = {# 'asdfasdfasdfas':{'k1':'v1','k2':'v2'}# 'asdfasdfasdfas':"{'k1':'v1','k2':'v2'}"
    }def __init__(self):pass# import redis# self.redis = redis.Redis()def _generate_sid(self):return str(uuid.uuid4())def _get_signer(self, app):if not app.secret_key:return Nonereturn Signer(app.secret_key, salt='flask-session',key_derivation='hmac')def open_session(self, app, request):"""程序刚启动时执行,需要返回一个session对象"""sid = request.cookies.get(app.session_cookie_name)if not sid:# 生成随机字符串,并将随机字符串添加到 session对象中sid = self._generate_sid()return self.session_class(sid=sid)signer = self._get_signer(app)try:sid_as_bytes = signer.unsign(sid)sid = sid_as_bytes.decode()except BadSignature:sid = self._generate_sid()return self.session_class(sid=sid)# session保存在redis中# val = self.redis.get(sid)# session保存在内存中val = self.container.get(sid)if val is not None:try:data = json.loads(val)return self.session_class(data, sid=sid)except:return self.session_class(sid=sid)return self.session_class(sid=sid)def save_session(self, app, session, response):"""程序结束前执行,可以保存session中所有的值如:保存到resit写入到用户cookie"""domain = self.get_cookie_domain(app)path = self.get_cookie_path(app)httponly = self.get_cookie_httponly(app)secure = self.get_cookie_secure(app)expires = self.get_expiration_time(app, session)val = json.dumps(dict(session))# session保存在redis中# self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)# session保存在内存中
        self.container.setdefault(session.sid, val)session_id = self._get_signer(app).sign(want_bytes(session.sid))response.set_cookie(app.session_cookie_name, session_id,expires=expires, httponly=httponly,domain=domain, path=path, secure=secure)app.session_interface = MySessionInterface()
# app.session_interface = Foo()
# app.session_interface
# app.make_null_session()
@app.route('/index')
def index():print('网站的所有session',MySessionInterface.container)print(session)session['k1'] = 'v1'session['k2'] = 'v2'del session['k1']# 在内存中操作字典....# session['k1'] = 'v1'# session['k2'] = 'v2'# del session['k1']return "xx"if __name__ == '__main__':app.__call__app.run()
View Code

 

转载于:https://www.cnblogs.com/yunweixiaoxuesheng/p/8445210.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据处理工具(一)——Matplotlib

文章目录致谢1 Matplotlib1.1 什么是Matplotlib1.2 实现一个简单的图1.3 Matplotlib三层结构1.3.1 容器层1.3.2 辅助显示层1.3.3 图像层1.3 使用模块1.3.1 画布的设置1.3.2 添加网格辅助背景1.3.3 附加属性1.3.4 标签1.3.5 刻度1.3.6 一个图上多条线1.3.7 子区域1.4 基础图表1.…

Java解析Rss(三)

2019独角兽企业重金招聘Python工程师标准>>> package com.ninemax.application.rss;import java.net.URL; import java.text.SimpleDateFormat; import java.util.List;import com.sun.syndication.feed.synd.SyndCategory; import com.sun.syndication.feed.synd.S…

Redis服务器启动之后3个警告信息的解决方案

今天是年前最后一篇文章了,不想写太多的东西,就写一些有关Redis相关问题的解决方案。当我们启动了Redis服务器之后,会看到3个警告,如果没看到,那是很好的,但是我看到了。看到了就不能不管,所以就…

ASP .NET MVC 之Entity Framework入门教程及源码

本文主要的目的是 1. 说明Entity Framework Power Tools如何使用。 2. Entity Framework 快速门 实验环境: OS: Windows Server 2012, Windows 7 DE: VS2013 MVC 6.0Entity Framework SQL Server 2012 准备工作 基于现有数据库生成POCO数据类和数据库上下文需要借…

机器学习的练功方式(六)——朴素贝叶斯

文章目录致谢6 朴素贝叶斯6.1 概述6.2 概率论6.2.1 大数定律6.2.2 基本概念6.2.3 极大似然估计6.2.4 多项式分布6.2.4.1 伯努利分布6.2.4.2 二项分布6.2.5 朴素贝叶斯6.3 朴素贝叶斯文本分类6.3.1 一个例子6.3.2 拉普拉斯平滑系数6.3.3 算法实现6.4 贝叶斯分类器6.4.1 多项式贝…

数据库杂谈(八)——查询优化

文章目录8 查询优化8.1 概述8.2 查询数和语法树8.3 代数优化8.4 物理优化8.5 连接操作优化8.5.1 嵌套循环法8.5.2 利用B树索引或哈希索引寻找匹配元组法8.5.3 散列连接法8.6 后话8 查询优化 8.1 概述 我们不管是在数据库软件如MySQL、SQLServer等,还是通过应用程序…

Android-入门学习笔记-使用 CursorLoader 加载数据

3 使用这个代码片段开始练习 也可以参考 Codepath 教程 高级内容补充: 你是否在思考ArrayAdapter’s 的 getView() 方法和CursorAdapter 的 newView() 和 bindView() 方法? 你可以查看 CursorAdapter 类的源码. getView() 方法依然存在, 但是它实际根据是否存在列表项能够被循…

在 Angularjs 中 ui-sref 和 $state.go 如何传递参数

1 ui-sref、$state.go 的区别 ui-sref 一般使用在 <a>...</a>&#xff1b; <a ui-sref"message-list">消息中心</a> $state.go(someState)一般使用在 controller里面&#xff1b; .controller(firstCtrl, function($scope, $state) {$state.…

机器学习的练功方式(七)——决策树

文章目录致谢7 决策树7.1 认识决策树7.2 决策树原理7.3 信息论7.3.1 信息熵7.3.1.1 熵7.3.1.2 信息7.3.1.3 信息熵7.3.2 信息增益7.4 决策树实现7.5 决策图7.6 后话致谢 信息熵是什么&#xff1f; - 知乎 (zhihu.com) 没有免费午餐定理_百度百科 (baidu.com) 7 决策树 决策树(…

机器学习的练功方式(八)——随机森林

文章目录致谢8 随机森林8.1 引入8.2 决策森林8.2.1 集成学习方法8.2.2 什么是随机森林8.2.3 无偏估计8.2.4 决策森林原理过程8.2.5 决策森林算法实现8.3 总结致谢 如何理解无偏估计&#xff1f;无偏估计有什么用&#xff1f;什么是无偏估计&#xff1f;_司南牧|知乎|博客|易懂教…

并行计算(一)——并行计算机系统及结构模型

致谢 SMP、COW、PVP、MPP计算机相关_神.秘.人的博客-CSDN博客_并行向量处理机 1 并行计算机系统及结构模型 1.1 并行计算 在下面的讲解之前&#xff0c;我们先看一下并行计算的量纲。 1.1.1 并行计算和计算机科学 随着计算机和计算机学科的发展&#xff0c;所有的学科都转向…

【机器学习实战】极大似然法

2019独角兽企业重金招聘Python工程师标准>>> http://baike.baidu.com/link?url3Ej1VIItwWd35sXeoRWRhcJkJLCFvzPzNIoTkAfai8ZIS4Ppcch4_maQ25FjNCU1Eplsp4k3oPKLyv6VIsPhsq 一、 最大似然法是一种具有理论性的点估计法&#xff0c;基本思想是&#xff0c;当从模型…

机器学习的练功方式(九)——线性回归

文章目录致谢9 线性回归再相遇9.1 再遇9.1.1 概述9.1.2 矩阵和向量9.1.3 矩阵加减乘除9.1.3.1 矩阵——矩阵加减9.1.3.2 矩阵——标量加减乘9.1.3.3 矩阵——向量相乘9.1.3.4 矩阵——矩阵相乘9.1.3.5 矩阵的逆9.1.3.6 矩阵的转置9.1.4 向量化9.1.5 广义线性模型9.2 正规方程9.…

12个月份统计分组

/** 根据月份来统计trade里面的入账&#xff0c;支出&#xff0c;总盈利*/public function countMonth(){$in array();$out array();$res array();$year date("Y",time());$in_sql SELECT SUM(money) AS mon, FROM_UNIXTIME(cdate, "%m") AS m FR…

idea 调试技巧1

1 多线程调试 开发过多线程应用的朋友应该有体会&#xff0c;有些时候&#xff0c;为了观察多个线程间变量的不同状态&#xff0c;以及锁的获取等&#xff0c;就会想到在代码里加个断点debug一下。 在IDE里断点停下来的时候&#xff0c;可以切换到另外的线程中&#xff0c;跑其…

SQL server 复习一

第一天 下面我们从最基础的开始&#xff1a; 在运行里面输入:services.msc 一、启动服务 二、数据库登录的两种身份验证方式 另外一种身份验证方式就是SQL Server身份验证. sa不能使用的时候可以这样的操作&#xff1a; 1.用windows登录&#xff0c;然后在“实例”右键“属性”…

[分享]iOS开发-实现view底部控件随着键盘的弹出而上移的效果

首先说一下思路&#xff1a;想要达到底部控件随着键盘的弹出而上移的效果&#xff0c;那么我们必然需要的到键盘在弹出时的高度&#xff0c;以及原点坐标。说白了我们的大致思路就是&#xff0c;用view的高度&#xff0d;键盘弹出时的高度&#xff0c;得到的值就是底部控件与vi…

深度学习修炼(二)——数据集的加载

文章目录致谢2 数据集的加载2.1 框架数据集的加载2.2 自定义数据集2.3 准备数据以进行数据加载器训练致谢 Pytorch自带数据集介绍_godblesstao的博客-CSDN博客_pytorch自带数据集 2 数据集的加载 与sklearn中的datasets自带数据集类似&#xff0c;pytorch框架也为我们提供了数…

Css3之基础-5 Css 背景、渐变属性

一、CSS 背景概述背景属性的作用- 背景样式可以控制 HTML 元素的背景颜色、背景图像等 - 背景色- 设置单一的颜色作为背景- 背景图像- 以图片作为背景- 可以设置图像的位置、平铺、尺寸等二、CSS 背景属性背景色 background-color - 属性用于为元素设置背景色- 接受任何合法的颜…

机器学习的练功方式(十)——岭回归

文章目录十 岭回归10.1 岭回归的接口10.2 岭回归处理房价预测十 岭回归 岭回归是线性回归的改进&#xff0c;有时候迫不得已我们的参数确实不能少&#xff0c;这时候过拟合的现象就可能发生。为了避免过拟合现象的发生&#xff0c;既然不能从减少参数上面下手&#xff0c;那我…