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,一经查实,立即删除!

相关文章

document.all

一.document.all是页面内所有元素的一个集合。例如: document.all(0)表示页面内第一个元素二.document.all可以判断浏览器是否是IE if(document.all){ alert("is IE!"); }三.也可以通过给某个元素设置id属性(idaaaa),然后…

数据处理工具(一)——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 多项式贝…

ABAP中创建动态内表的三种方法(转载)

BAP中创建动态内表的三种方法 第一种: 如果我们需要的动态内表字段或者动态工作区和数据字典中的类型一致,可以直接使用CREATE DATA生成,当然也可以是自定义类型。 比如要产生和数据表MARA结构一致的动态内表: DATA : DY_TABLE TYPE REF TO D…

个人简介

我叫范华万,今天22岁,来自于福建省。目前在闽江学院就学。我学的是软件工程软件服务开发专业,能从事网站设计、java工程师、ps技术、c、数据库管理。本人性格乐观、开朗,有上进心、进取心,对学习认真负责,I…

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

文章目录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() 方法依然存在, 但是它实际根据是否存在列表项能够被循…

逆向思维求素数

1 #include <stdio.h>2 3 int main(void)4 {5 const int len 100;6 int prime[len];7 for (int i0; i<len; i)8 prime[i] 1; // 1 标记这个序号数为素数&#xff0c;0标记为非素数9 for (int x2; x<len; x) 10 { 11 for (in…

在 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 决策树 决策树(…

[BZOJ3583]杰杰的女性朋友(矩阵快速幂)

杰杰的女性朋友 时间限制&#xff1a;10s 空间限制&#xff1a;256MB 题目描述 杰杰是魔法界的一名传奇人物。他对魔法具有深刻的洞察力&#xff0c;惊人的领悟力&#xff0c;以及令人叹为观止的创造力。自从他从事魔法竞赛以来&#xff0c;短短几年时间&#xff0c;就已经…

13.程序集篇

1.定义 程序集是.net框架应用程序生成块&#xff0c;它包含编译好的代码逻辑单元。 2.结构 程序集有描述他的程序清单、类型元数据&#xff0c;MSIL代码和资源组成。 程序集清单&#xff1a; 每一个程序集都包含描述该程序集中的各个元素彼此如何关联的数据集合。程序集清单包含…

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

文章目录致谢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;_司南牧|知乎|博客|易懂教…

E20180219-hm-xa

comparison n. 比较&#xff0c;对照; [语] 比喻; 比较级; conjunction n. 连接; 连词; 联合&#xff0c;结合物; &#xff08;恒星、行星等的&#xff09; 合; [例句] assignment n. 分给&#xff0c;分配; 任务&#xff0c;工作&#xff0c;&#xff08;课外&#xff09;作…

这是我看过最精彩的回答

或许我没见过世面&#xff0c;但是这却是我看过对“怎么成为一个优秀的程序员&#xff0c;而不是一个优秀的码农&#xff1f;”最精彩的回答【全部复制粘贴】 其实我的心一直因为现在的工作【餐饮服务】而动摇&#xff0c;忽而想学网站&#xff0c;忽而c语言根基&#xff0c;忽…

免费LInux主机资源

一、m-net.arbornet.org注冊 &#xff08;1&#xff09;telnet m-net.arbornet.org vista系统默认是关闭telnet的&#xff08;由于不安全&#xff09;&#xff0c;须要开启。cmd->telnet&#xff08;2&#xff09;login:newuser password: (3) ssh m-net.arbornet.org vi的…

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

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