用Python实现单例模式
什么是单例模式
单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。
单例模式的应用场景
单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。
单例模式的优缺点
优点:
1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3.提供了对唯一实例的受控访问。
4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5.允许可变数目的实例。
6.避免对共享资源的多重占用。
缺点:
1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3.单例类的职责过重,在一定程度上违背了“单一职责原则”。
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
实现单例模式的几个实例
使用类变量实现单例模式
在 Python 中,可以通过定义一个类变量来实现单例模式,这个类变量可以存储单例实例的引用,如果该变量已经存储了一个实例,就直接返回该实例的引用,否则就创建一个新实例并将其存储在类变量中。
class Singleton:__instance = None # 用于存储单例实例的类变量def __new__(cls):if cls.__instance is None:cls.__instance = super().__new__(cls)return cls.__instances1 = Singleton()
s2 = Singleton()
print(s1 == s2) # True,因为 s1 和 s2 引用的是同一个实例在这个例子中,我们定义了一个名为 `Singleton` 的类,它有一个类变量 `__instance`,用于存储单例实例的引用。在类的构造方法 `__new__` 中,我们首先检查 `__instance` 是否为 None,如果是,则说明还没有创建实例,于是调用父类的 `__new__` 方法创建一个新实例并将其赋值给 `__instance`,然后返回该实例的引用。如果 `__instance` 不为 None,则说明已经存在一个实例,于是直接返回该实例的引用。
最后,我们创建了两个 `Singleton` 类的实例 `s1` 和 `s2`,并将它们分别赋值给变量 `s1` 和 `s2`。由于单例模式的特性,我们期望 `s1` 和 `s2` 引用的是同一个实例,因此打印 `s1 == s2` 的结果应该为 True。除了使用类变量存储单例实例的引用之外,还可以使用装饰器或元类来实现单例模式。
使用装饰器实现单例模式
def singleton(cls):instances = {}def getinstance(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return getinstance@singleton
class MyClass:passa = MyClass()
b = MyClass()
print(a == b) # True,因为 a 和 b 引用的是同一个实例在这个例子中,我们定义了一个名为 `singleton` 的装饰器,它会接受一个类作为参数,返回一个新的函数 `getinstance`。在 `getinstance` 函数中,我们首先检查 `cls` 是否在 `instances` 字典中,如果不在,则说明还没有创建实例,于是调用 `cls` 的构造方法创建一个新实例并将其存储在 `instances` 中,然后返回该实例的引用。如果 `cls` 已经在 `instances` 中,则直接返回该实例的引用。最后,我们用 `@singleton` 装饰器修饰了一个名为 `MyClass` 的类,使其成为单例类。
使用元类实现单例模式
class Singleton(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super().__call__(*args, **kwargs)return cls._instances[cls]class MyClass(metaclass=Singleton):passa = MyClass()
b = MyClass()
print(a == b) # True,因为 a 和 b 引用的是同一个实例在这个例子中,我们定义了一个名为 `Singleton` 的元类,它会在每次创建类时被调用。在 `Singleton` 的 `__call__` 方法中,我们首先检查 `cls` 是否在 `_instances` 字典中,如果不在,则说明还没有创建实例,于是调用父类的 `__call__` 方法创建一个新实例并将其存储在 `_instances` 中,然后返回该实例的引用。如果 `cls` 已经在 `_instances` 中,则直接返回该实例的引用。最后,我们用 `metaclass=Singleton` 指定了一个元类,使其成为 `MyClass` 的元类,从而使 `MyClass` 成为单例类。除了上述的几种实现方式外,还有其他的一些实现单例模式的方法。
使用模块实现单例模式
在 Python 中,模块在导入时只会被执行一次,因此可以使用模块来实现单例模式。例如,我们可以创建一个名为 `mysingleton.py` 的模块,并在其中定义一个单例类:
class MySingleton:def __init__(self):self.name = "Singleton"my_singleton = MySingleton()在另一个文件中,我们可以导入 `mysingleton` 模块,并使用其中的单例对象 `my_singleton`:
from mysingleton import my_singleton
print(my_singleton.name) # "Singleton"在这个例子中,我们在 `mysingleton.py` 模块中定义了一个名为 `MySingleton` 的单例类,并在该类的构造方法中定义了一个名为 `name` 的实例变量。在该模块中,我们还创建了一个名为 `my_singleton` 的 `MySingleton` 类的实例,并将其赋值给一个全局变量。在另一个文件中,我们通过 `from mysingleton import my_singleton` 导入了 `my_singleton` 对象,并打印了它的 `name` 变量。
使用闭包实现单例模式
在 Python 中,闭包是一种可以捕获其定义域中的变量并将其封装在函数对象中的方法。可以使用闭包来实现单例模式。例如,我们可以创建一个函数 `singleton`,它会返回一个内部函数 `get_instance`,该函数用于创建并返回单例对象:
def singleton(cls):instance = Nonedef get_instance(*args, **kwargs):nonlocal instanceif instance is None:instance = cls(*args, **kwargs)return instancereturn get_instance@singleton
class MyClass:passa = MyClass()
b = MyClass()
print(a == b) # True,因为 a 和 b 引用的是同一个实例在这个例子中,我们定义了一个名为 `singleton` 的函数,它接受一个类作为参数,并返回一个内部函数 `get_instance`。在 `get_instance` 函数中,我们首先声明一个名为 `instance` 的变量,并将其初始化为 None。然后,我们检查 `instance` 是否为 None,如果是,则说明还没有创建实例,于是调用 `cls` 的构造方法创建一个新实例并将其赋值给 `instance`,然后返回该实例的引用。如果 `instance` 不为 None,则说明已经存在一个实例,直接返回该实例的引用。最后,我们用 `@singleton` 装饰器修饰了一个名为 `MyClass` 的类,使其成为单例类。
使用单例模式的注意事项
在使用单例模式时,需要注意以下几点:
确保单例类的唯一性:单例类应该只有一个实例,并且该实例应该在整个程序中都可用。因此外,还需要注意以下几点:
线程安全:如果多个线程同时调用单例类的构造方法,可能会创建多个实例。因此,需要采取线程安全的措施,如使用锁或原子操作。
生命周期管理:由于单例对象在整个程序中都可用,因此需要考虑它的生命周期。单例对象可能需要在程序退出时进行清理操作,例如关闭数据库连接或保存缓存数据。
依赖管理:如果单例对象依赖于其他对象,则需要确保这些依赖对象也是单例对象。否则,可能会出现多个实例之间的状态不一致的问题。
总之,单例模式是一种非常有用的设计模式,它可以确保一个类只有一个实例,并且该实例在整个程序中都可用。在 Python 中,可以使用多种方式实现单例模式,如使用类装饰器、元类、模块、闭包等。在实现单例模式时,需要考虑线程安全、生命周期管理和依赖管理等问题,以确保单例对象的正确性和可靠性。
相关文章:
用Python实现单例模式
什么是单例模式单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象…...
交叉编译说明:工具链安装和环境变量配置
目录 一 简单了解交叉编译 ① 什么是交叉编译 ② 为什么需要交叉编译 ③ 宿主机和目标机 二 搭建交叉编译工作环境 ① 安装工具链 ② 配置环境变量 ● 配置临时环境变量 ● 配置永久环境变量 三 交叉编译宿主机和目标机 ● 宿主机编译生成的可执行文件下载到目…...
文件上传的多种利用方式
文件上传的多种利用方式 文件上传漏洞除了可以通过绕过检测进行webshell的上传之外,还有多种其它的漏洞可以进行测试。 XSS漏洞 文件名造成的XSS 当上传任何文件时,文件名肯定是会反显示在网页上,可以使用 XSS Payload做文件名尝试将其上传到…...
盘一盘C++的类型描述符(二)
先序文章请看 盘一盘C的类型描述符(一) 稍微组合一下的复杂类型 数组指针类型的数组类型 数组的指针类型我们已经了解了,那么,以这种类型作为元素的数组类型怎么搞? using type int (*)[3]; // 元素类型是数组指针…...
慎投,Frontiers这本期刊显示on hold中
什么是“On Hold”? 该期刊因为质量问题正在被进行重新评估;在重新评估过程中,不会检索新发表的文章。该期刊因为质量问题正在被进行重新评估;在重新评估过程中,不会检索新发表的文章。根据选择标准,在最严…...
Winform控件开发(21)——ProgressBar(史上最全)
一、属性 1、Name 用于获取控件对象 2、Anchor 锚定控件对于父控件的位置 3、BackColor 背景色 4、ContextMenuStrip 关联的上下文菜单 5、Cursor 鼠标移动到控件上显示的光标 6、Dock 停靠在父控件的位置 7、Enabled 是否启动该控件,false时事件都不能触发 8、…...
校招失败后,在外包公司熬了 2 年终于进了字节跳动,竭尽全力....
其实两年前校招的时候就往字节投了一次简历,结果很明显凉了,随后这个理想就被暂时放下了,但是这个种子一直埋在心里这两年除了工作以外,也会坚持写博客,也因此结识了很多优秀的小伙伴,从他们身上学到了特别…...
UniApp + SpringBoot 实现接入支付宝支付功能和退款功能
一、支付宝开放平台设置 注册支付宝支付功能需要个体工商户或企业才可以!需要有营业执照才能去申请哦! 1、登录到控制台 进入支付宝开放平台 控制台 2、开发设置 3、产品绑定APP支付 如果没有绑定APP支付就会报商家订单参数异常,请重新发起…...
初识进程
文章目录一、进程的概念1. 进程是什么及进程的管理2. Linux 下的 pcb3. 系统调用接口 getpid 和 getppid4. 系统调用接口 fork一、进程的概念 1. 进程是什么及进程的管理 在 Linux下 ./binaryfile 运行一个程序或者在 Windows下双击运行一个程序时,程序就变成了一个…...
SOAP传输协议
一.HTTP传输协议 超文本传输协议(HyperText Transfer Protocol,缩写:HTTP),它是基于请求-响应的模式协议,客户端发出请求,服务器端给出响应并返回请求内容。方法如下,HTTP传输协议常…...
<Linux>进程控制
进程控制 文章目录进程控制一、进程创建1.fork函数认识2.写时拷贝3.fork常规用法4.fork调用失败的原因二、进程终止1.进程退出场景2.进程退出码3.进程退出的方式三、进程等待1.进程等待是什么?2.进程等待的必要性3.进程等待的方法3.1.wait函数3.2.waitpid函数4.如何…...
有手就行 -- 搭建图床(PicGo+腾讯云)
🍳作者:贤蛋大眼萌,一名很普通但不想普通的程序媛\color{#FF0000}{贤蛋 大眼萌 ,一名很普通但不想普通的程序媛}贤蛋大眼萌,一名很普通但不想普通的程序媛🤳 🙊语录:多一些不为什么的…...
“蓝桥杯”递推和递归(一)——取数位
1. 算法简介 递推和递归虽然叫法不同,但它们的基本思想是一致的,在很多程序中,这两种算法可以通用,不同的是递推法效率更高,递归法更方便阅读。 (1)递推法 递推法是一种重要的数学方法&#…...
蓝桥杯·3月份刷题集训Day02
本篇博客旨在记录自已打卡蓝桥杯3月份刷题集训,同时会有自己的思路及代码解答希望可以给小伙伴一些帮助。本人也是算法小白,水平有限,如果文章中有什么错误之处,希望小伙伴们可以在评论区指出来,共勉💪。 文…...
python --获取内网IP地址
方法一 import socketdef get_local_ip_address():ip_address try:# 获取本机主机名hostname socket.gethostname()# 获取本机IPip_address socket.gethostbyname(hostname)except:passreturn ip_address方法二 import subprocessdef get_local_ip_address():ip_address …...
如何衡量你的Facebook广告活动的成功
投入大量资金和资源在Facebook广告上并不总能带来预期的回报,这很可能是由于缺乏恰当的衡量广告活动成功的方法。在这篇文章中,我们将介绍一些关键的指标,帮助你更好地了解如何衡量你的Facebook广告活动的成功。1.费用每次点击(CP…...
Linux对一个目录及其子目录所有文件添加权限
1、chmod指令 chmod是一个改变用户拥有指定文件的权限的命令.r:只读,w:写,x执行.也可以用数字 -rw------- (600) -- 只有属主有读写权限。 -rw-r--r-- (644) -- 只有属主有读写权限;而属组用户和其他用户只有读权限。 -rwx------ (700) -- 只有属主有读、写、执…...
宝刀未老?低代码何德何能受大厂们的推崇
风口之下,低代码蓬勃发展,本文从国内低代码的走红现象引入,浅析低代码发展中的变化趋势,重点探讨如此趋势之下,国内大厂如何通过低代码实现了良性发展。 一、国内爆火的低代码 据Gartner最新报告显示,到2…...
智能扑克牌识别软件(Python+YOLOv5深度学习模型+清新界面)
摘要:智能扑克牌识别软件利用视觉方法检测和识别日常扑克牌具体花色与数字,快速识别牌型并标注结果,帮助计算机完成扑克牌对战的前期识别步骤。本文详细介绍基于深度学习的智能扑克牌识别软件,在介绍算法原理的同时,给…...
SQL优化13连问,收藏好!
1.日常工作中,你是怎么优化SQL的? 大家可以从这几个维度回答这个问题: 分析慢查询日志 使用explain查看执行计划 索引优化 深分页优化 避免全表扫描 避免返回不必要的数据(如select具体字段而不是select*) 使用…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
