当前位置: 首页 > news >正文

用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` 的类,使其成为单例类。

使用单例模式的注意事项

在使用单例模式时,需要注意以下几点:

  1. 确保单例类的唯一性:单例类应该只有一个实例,并且该实例应该在整个程序中都可用。因此外,还需要注意以下几点:

  1. 线程安全:如果多个线程同时调用单例类的构造方法,可能会创建多个实例。因此,需要采取线程安全的措施,如使用锁或原子操作。

  1. 生命周期管理:由于单例对象在整个程序中都可用,因此需要考虑它的生命周期。单例对象可能需要在程序退出时进行清理操作,例如关闭数据库连接或保存缓存数据。

  1. 依赖管理:如果单例对象依赖于其他对象,则需要确保这些依赖对象也是单例对象。否则,可能会出现多个实例之间的状态不一致的问题。

总之,单例模式是一种非常有用的设计模式,它可以确保一个类只有一个实例,并且该实例在整个程序中都可用。在 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*) 使用…...

【小技巧】公式从docx文件复制到doc文件变成了图片怎么办?

文章目录0、word文件后缀命名1、docx和doc默认的公式编辑方式2、MathTpye公式编辑器3、MathType 运行时错误‘53’:文件未找到:MathPage.WLL4、结束语0、word文件后缀命名 1997-2003的旧版本文件名后缀是.doc   从2007版以后,后缀名是.docx…...

Python3入门与进阶笔记(六):初识类

目录 一些解释 属性 类名建议首字母大写,通常用驼峰规则命名。变量名建议小写,下划线隔开。类最基本的作用是封装。 写在类内非方法中的语句在类加载的时候会执行,且只会执行一次,例如下面的print语句,类加载时就会…...

Prometheus监控实战系列九:主机监控

Prometheus使用各种Exporter来监控资源。Exporter可以看成是监控的agent端,它负责收集对应资源的指标,并提供接口给到Prometheus读取。不同资源的监控对应不同的Exporter,如node-exporeter、mysql-exporter、kafka-exporter等,在这…...

JVM知识整理

JVM知识整理 JVM的主要组成部分 JVM包含两个两个子系统(类加载子系统和执行引擎)和两个组件(运行时数据区与和本地库接口) 类加载子系统:根据给定的全限定类名来加载class文件到运行时数据区域中的方法区。执行引擎&a…...

【C++】二叉搜索树

A:你长大后想要做什么? B:写下“快乐”…… A:不,你理解错我的意思了,我是说 B:不,是你理解错了人生…… 文章目录一、二叉搜索树的实现1.struct TreeNode{}2.迭代版本2.1 Insert()插入结点(解决链接的问题&#xff09…...

leetcode -- 21. 合并两个有序链表

🐨目录📑1. 题目🛶2. 解法- 头插到新链表🐬2.1 思路🐬2.1 代码实现⛵3. 解法优化 - 带哨兵位🐋3.1 思路🐋3.2 代码实现🚤4. 题目链接📑1. 题目 将两个升序链表合并为一个…...

计算机组成原理|第四章(笔记)

目录第四章 存储器4.1 概述4.1.1 存储器分类4.1.2 存储器的层次结构4.2 主存储器4.2.1 概述4.2.2 半导体存储芯片简介4.2.3 随机存取存储器(RAM)4.2.4 只读存储器(ROM)4.2.5 存储器与CPU的连接4.2.6 存储器的校验4.2.7 提高访存速…...

【Unity3D-BUG记录】Unity3D中出现“动画片段必须标记为Legacy的警告”消除方法

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 在开发中可能会遇到下面的警告: The AnimationClip…...

Spring Bean的定义(含创建Bean的三种方式)

🏆 文章目标:复习和理解下Spring Bean的定义 🍀 Spring Bean的定义(含创建Bean的三种方式) ✅ 创作者:Jay… 🎉 个人主页:Jay的个人主页 🍁 展望:若本篇讲解内…...

vue的路由-vue router(一)

vue的路由-vue router一、路由的基本使用HTMLrouter-linkrouter-viewJavaScript二、带参数的动态路由匹配三、嵌套路由四. 编程式导航导航到不同的位置替换当前位置横跨历史篡改历史五. 命名路由六. 命名视图嵌套命名视图七. 重定向和别名重定向别名八. 将 props 传递给路由组件…...

北京西站附近的景点有哪些/东莞网站开发公司

说明:ABAP/4 编辑器 "插入" 命令 当使用 ABAP 编辑器的“模式”功能插入程序对象时,自动生成的代码。 字段列表 APP_OBJ EDEDOBJECT CHAR 4 0 EDIC: 编辑器目标 KEYWORD EDKEYWORD CHAR 20 0 ABAP/4 编辑器关键词 POSITION EDPOSITION NUMC 2…...

做企业的网站/seo零基础教学视频

1、到相应站点下载Smarty的源码包; 2、将源码包里面的libs文件夹copy到CI的项目目录下面的libraries文件夹下,并重命名为Smarty; 3、在项目目录的libraries文件夹内新建文件Cismarty.php,里面的内容如下: view sourcep…...

可以先做网站再开公司吗/网络营销具有哪些优势和吸引力

浏览器内核是什么东东 Rending Engine, 顾名思义,称之为渲染网页内容的,将网页的代码转换为你看得见的页面,因为是排版,所以排版,所以肯定会有排版错误等问题。为什么会有排版错误呢,一部分是由于网站本身编…...

政务公开网站建设重点/怎么样免费做网站

为了快速管理数据库,我们一般都会选择一款顺手的数据库管理工具。Navicat、DataGrip虽然很好用,但都是收费的。今天给大家推荐一款免费、功能强大的数据库管理工具DBeaver,希望对大家有所帮助! SpringBoot实战电商项目mall&#x…...

深圳网站建设最好/电话销售外呼系统软件

​​​​​​​开发十年,就只剩下这套Java开发体系了 >>> 1、私服简介 私服是架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件。有了私服之后,当 Maven 需要下载构件时,直接请求私服&#xff0…...

wordpress poiplayer/如何推广品牌知名度

如何解决Activiti-modeler无法使用的问题 之前学习Activity的时候在网上面找了各种关于modeler使用说明,但是往往必须非常严格的按照教程的路线进行使用。 一、了解modeler需要些什么才能够正常运作 首先就是将activity框架搞定,如果连这个都没有的话也就…...