python中实现单例模式
单例模式的目的是一个类有且只有一个实例对象存在,比如在复用类的过程中,可能重复创建多个实例,导致严重浪费内存,此时就适合使用单例模式。
前段时间需要用到单例模式,就称着机会在网上找了找,有包含了__new__方法在内的5种单例模式,就顺便记录于此。
基于模块导入机制的实现
第一次执行程序时编译为.pyc文件,而第二次执行时会直接执行.pyc。基于此机制,可以通过把类和所创建的实例单独写在某模块内,在使用时直接从这么模块中导入即可,这个导入的实例对象即唯一对象。
# test.py文件
class Test(object):
pass
# 创建实例对象
t = Test() # 在其他文件中
from test import t
基于装饰器的实现
def singleton(cls):
instance = None def wrap(*argrs, **kwargs):
nonlocal instance
if instance is None:
instance = cls(*args, **kwargs)
return instance return wrap @singleton
class Test(object): def __init__(self, *args, **kwargs):
pass t1 = Test()
t2 = Test()
print(t1 is t2) # 输出True
基于类(类方法)的实现(这个看别人的博客学来的)
class Test(object): def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
# 每次调用此类方法即可创建实例对象
if not hasattr(Test, "_instance"):
Test._instance = Test(*args, **kwargs)
return Test._instance
上述的实现方法在使用多线程时会出现问题,即这种上述实现单例模式不支持多线程
import threading
import time class Test(object): def __init__(self):
time.sleep(2) @classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Test, "_instance"):
Test._instance = Test(*args, **kwargs)
return Test._instance def task(args):
obj = Test.instance()
print(obj) for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
注意,如果上述不用sleep()暂停,执行速度过快时,仍可能存在相同地址
解决方法:加锁
import threading
import time class Test(object):
_instance_lock = threading.Lock() def __init__(self):
time.sleep(2) @classmethod
def instance(cls, *args, **kwargs):
with Test._instance_lock:
if not hasattr(Test, "_instance"):
Test._instance = Test(*args, **kwargs)
return Test._instance def task(args):
obj = Test.instance()
print(obj) for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start() # 检查长时间后是否为单例
time.sleep(20)
obj = Test.instance()
print(obj)
上述方案长时间后虽然仍为单例模式,但是仍处于加锁的状态,可通过将锁的位置放在判断实例是否存在之后,如果不存在需要重新创建时再加锁
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Test, "_instance"):
with Test._instance_lock:
Test._instance = Test(*args, **kwargs)
return Test._instance
上述这种方法的问题在于创建实例对象时是通过调用Test.instance()创建的,而不是常规那样创建
基于__new__方法的实现(最常见)
在创建一个实例对象时,先调用__new__方法,再调用__init__方法
import threading
import time
class Test(object): def __init__(self):
time.sleep(1) def __new__(cls, *args, **kwargs):
if not hasattr(Test, "_instance"):
Test._instance = object.__new__(cls) # 相当于继承
return Test._instance obj1 = Test()
obj2 = Test()
print(obj1, obj2) def task(arg):
obj = Test()
print(obj) for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
也可像之前装饰器一样用一个类属性来判断是否已有创建好的实例对象,如果没有则在__new__中创建,注意必须返回实例对象
这种方法不受线程影响
基于元类方法的实现
python中是类由type创建,在创建时类时会先调用type的__init__方法,然后创建实例对象时会调用type的__call__方法
顺序如下:type的__init__方法(创建类) -> type的__call__方法(类创建实例对象) -> 类的__new__方法(类创建实例对象) -> 类的__init__方法(类初始化实例对象)
元类的使用方式就是写一个继承了type的类,然后在我们所需的类中指定元类(通过metaclass参数),而继承了type的类则可重新定义类的构造函数,单例模式则可在__call__方法中定义
class SingletonType(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance class Test(metaclass=SingletonType):
def __init__(self):
pass obj1 = Test()
obj2 = Test()
print(obj1,obj2)
注意:在元类中__call__的参数cls指所创建的类
python中实现单例模式的更多相关文章
- Python学习笔记之在Python中实现单例模式
有些时候你的项目中难免需要一些全局唯一的对象,这些对象大多是一些工具性的东西,在Python中实现单例模式并不是什么难事.以下总结几种方法: 使用类装饰器 使用装饰器实现单例类的时候,类本身并不知道自 ...
- Python中的单例模式
在 Python 中,我们可以用多种方法来实现单例模式: 使用模块 使用 __new__ 使用装饰器(decorator) 使用元类(metaclass) # mysingleton.py class ...
- Python中的单例模式的几种实现方式的优缺点及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python 中的单例模式
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python中的单例模式——装饰器实现剖析
Python中单例模式的实现方法有多种,但在这些方法中属装饰器版本用的广,因为装饰器是基于面向切面编程思想来实现的,具有很高的解耦性和灵活性. 单例模式定义:具有该模式的类只能生成一个实例对象. 先将 ...
- python中的单例模式、元类
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python中的单例模式的几种实现方式的及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- python中的单例模式的应用
1 使用__new__方法 class Singleton(object): def __new__(cls, *args, **kw): if not hasattr(cls, ...
- Python中的单例模式的几种实现方式和优化以及pyc文件解释(转)
原文:https://www.cnblogs.com/huchong/p/8244279.html 另一篇关于.pyc文件是什么? 原文: http://blog.sina.com.cn//s/bl ...
随机推荐
- 剑指Offer-33.第一个只出现一次的字符(C++/Java)
题目: 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写). 分析: 遍历字符串,利用Ha ...
- bzoj3293 分金币
题目链接 problem 圆桌上坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一些金币,最终使 得每个人的金币数目相等.你的任务是求出被转手的金币数量的最小值. so ...
- 2019CSP-J/S受虐记
emmmm...... 今年noip很波折,我从7月开始准备 但CCF居然停了noip,这搞得我很迷茫,CCF你在干什么! 然后又恢复了,这有搞得我很懵逼?(还改名叫csp了) 就换了个名,CCF你搞 ...
- 用 Python 批量下载百度图片
为了做一个图像分类的小项目,需要制作自己的数据集.要想制作数据集,就得从网上下载大量的图片,再统一处理. 这时,一张张的保存下载,就显得很繁琐.那么,有没有一种方法可以把搜索到的图片直接下载到本地 ...
- 从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结
一.引言 移动互联网技术改变了旅游的世界,这个领域过去沉重的信息分销成本被大大降低.用户与服务供应商之间.用户与用户之间的沟通路径逐渐打通,沟通的场景也在不断扩展.这促使所有的移动应用开发者都要从用户 ...
- 细数使用View UI(iView)开发中遇到的坑
一.前言 View UI,即原先的 iView,是一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品. 官网地址:https://www.iviewui.com/docs ...
- Windows Store无法联网时安装WSL
Windows Store无法联网时安装WSL 1 打开powershell 输入命令: Invoke-WebRequest -Uri https://aka.ms/wsl-ubuntu-1604 - ...
- Nginx 转发页面跳转重定向
简介 Nginx在反向代理过程中,通过重定向跳转时会找不到URL.是因为经常没有配置Host header 的端口,需要如下标红部分一样配置端口号. 只添加Host重定向之后,就会没有端口号. 方案 ...
- pandas 学习 第8篇:Index 对象 - (创建、转换、排序)
Index对象负责管理轴标签.轴名称等元数据,是一个不可修改的.有序的.可以索引的ndarry对象.在构建Sereis或DataFrame时,所用到的任何数据或者array-like的标签,都会转换为 ...
- MySQL 联表查询
关系型数据库,免不了表之间存在各种引用与关联.这些关联是通过主键与外键搭配来形成的.所以,取数据时,很大情况下单张表无法满足需求,额外的数据则需要将其他表加入到查询中来,这便是 JOIN 关键字完成的 ...