(三)python单例模式

文章目录

      • 一、单例模式介绍
        • 1.1 应用场景:
      • 二、单例模式的几种创建方式:
        • 2.1.经典模式创建:
        • 2.2 懒汉式创建
        • 2.3 模块级别的单例模式
        • 2.4 Monostate单例模式(单态)
        • 2.5 单例和元类
          • 2.5.1 什么是元类
          • 2.5.2 自定义元类
          • 2.5.3 基于元类方式的单例创建
      • 三、单例模式的缺点

一、单例模式介绍

单例设计模式是应用开发过程中最简单和最著名的一种创建型设计模式。

1.1 应用场景:
  • 配置管理:在应用程序中,通常会有一些全局配置,例如数据库连接、日志记录器等。使用单例模式可以确保只有一个配置实例,并且可以在整个应用程序中访问该实例。
  • 日志记录:日志记录器通常只需要一个实例。使用单例模式可以确保在整个应用程序中只有一个日志记录器实例,并且可以轻松地访问它。
  • 缓存:缓存通常只需要一个实例。使用单例模式可以确保在整个应用程序中只有一个缓存实例,并且可以轻松地访问它。
  • 线程池:线程池通常只需要一个实例。使用单例模式可以确保在整个应用程序中只有一个线程池实例,并且可以轻松地访问它。

二、单例模式的几种创建方式:

2.1.经典模式创建:

实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后,这个类将返回同一个对象。
在使用 Python 的时候,我们的实现方式要有所变通,因为它无法创建私有的构造函数。下面,我们一起看看如何利用Python语言来实现单例模式。

class Singleton(object):def __new__(cls, *args, **kwargs):if not hasattr(cls, 'instance'):cls.instance = super(Singleton, cls).__new__(cls)return cls.instance
s = Singleton()
print("1-对象创建", s)
s2 = Singleton()
print("2-对象创建", s2)

在上面的代码中,我们通过覆盖__new__方法(python用来实例化对象的特殊方法)来控制对象的创建。对象s就是由__new__方法创建的。
方法hasattr用于查看对象是否具有属性instance,该属性的作用是检查该类是否已经生成了一个对象。

2.2 懒汉式创建

单例模式的用例之一就是懒汉式实例化。例如,在导入模块的时候,我们可能会无意中创建一个对象,但当时根本用不到它。懒汉式实例化能够确保在实际需要时才创建对象。所以,懒汉式实例化是一种节约资源并仅在需要时才创建它们的方式。
在下面的代码示例中,执行 s= singleton()的时候,它会调用 init 方法但没有新的对象被创建。然而,实际的对象创建发生在调用 singleton.getInstance()的时候,我们正是通过这种方式来实现懒汉式实例化的。

class Singleton:_instance = Nonedef __init__(self):if not Singleton._instance:print("类已初始化,但实例未创建!")else:print("实例已创建", self.getInstance())@classmethoddef getInstance(cls):if not cls._instance:cls._instance = Singleton()return cls._instance
s = Singleton()  # 类已初始化,但未创建对象
print("开始创建对象", Singleton.getInstance())
s1 = Singleton()  # 此时对象已存在,不再创建新的
2.3 模块级别的单例模式

默认情况下,所有的模块都是单例,这是由 Python的导入行为所决定的
Python通过下列方式来工作。

  1. 检查一个Python模块是否已经导入。
  2. 如果已经导入,则返回该模块的对象。如果还没有导入,则导入该模块,并实例化。
  3. 因此,当模块被导入的时候,它就会被初始化。然而,当同一个模块被再次导入的时候,它不会再次初始化,因为单例模式只能有一个对象,所以,它会返回同一个对象。
2.4 Monostate单例模式(单态)

在Monostate单例模式中,一个类有且只有一个对象,但与传统的单例模式不同的是,它关注的是实例的状态,而不是实例本身。因此,Monostate单例模式适合于需要让多个实例共享相同状态的情况。
Monostate单例模式的应用场景包括日志记录、数据库操作、打印机后台处理程序等,这些程序在运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求。

class Borg:__shared_state = {"x": "1"}def __init__(self):self.y = 2#  __dict__ python内置,用来存储一个类所有对象的状态self.__dict__ = self.__shared_state
b = Borg()
b1 = Borg()
b.y = 4  # y的属性被所有对象共享
print(b)
print(b1)  # 地址是不同的,
print(b.__dict__)
print(b1.__dict__)  # 两个对象的状态是一致的!
2.5 单例和元类
2.5.1 什么是元类

元类是一个类的类,这意味着该类是它的元类的实例。使用元类,程序员有机会从预定义的 Python 类创建自己类型的类。

例如,如果你有一个对象Myclass,你可以创建一个元类MyKls,它按照你需要的方式重新定义Myclass 的行为。

在Python中,一切皆对象。如果我们说a=5,则type(a)返回<type ‘int’>,这意味着a是int 类型。但是,type(int)返回<type ‘type’>,这表明存在一个元类,因为int是type类型的类。

类的定义由它的元类决定,所以当我们用类A创建一个类时,Python 通过A=type(name,bases,dict)创建它。其中,name-类的名称; bases-基类; dict-属性变量;

2.5.2 自定义元类

现在,如果一个类有一个预定义的元类(名为 MyInt),那么 Python 就会通过A=MyInt(name,bases,dict)来创建类。

class MyInt(type):def __call__(cls, *args, **kwds):print("***** Here's My int *****args")print("Now do whatever you want with these objects...")return type.__call__(cls, *args, **kwds)
class int(metaclass=MyInt):def __init__(self, x, y):self.x = xself.y = y
i = int(4, 5)

对于已经存在的类来说,当需要创建对象时,将调用 Python 的特殊方法__call__,在这段代码中,当我们使用int(4,5)实例化int 类时MyInt 元类的 call 方法将被调用,这意味着现在元类控制着对象的实例化。

2.5.3 基于元类方式的单例创建

前面的思路同样适用于单例设计模式。由于元类对类创建和对象实例化有更多的控制权,所以它可以用于创建单例。(注意:为了控制类的创建和初始化,元类将覆盖 __new__和 init 方法。)

  • 日志类的实现:
class MetaSingleton(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)return cls._instances[cls]
class Logger(metaclass=MetaSingleton):pass
logger1 = Logger()
logger2 = Logger()
print(logger1, logger2)
  • 数据库连接池的实现
import sqlite3
class MetaSingleton(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)return cls._instances[cls]
class Database(metaclass=MetaSingleton):connection = Nonedef connect(self):if self.connection is None:self.connection = sqlite3.connect("db.sqlite3")self.cursorobj = self.connection.cursor()return self.cursorobj
db1 = Database().connect()
db2 = Database().connect()
print("Database Objects DB1", db1)
print("Database Objects DB2", db2)  #  可以看出两个结果是一致的

三、单例模式的缺点

虽然单例模式在许多情况下效果很好,但这种模式仍然存在一些缺陷。由于单例具有全局访问权限,因此可能会出现以下问题

● 全局变量可能在某处已经被误改,但是开发人员仍然认为它们没有发生变化,而该变量还在应用程序的其他位置被使用。
● 可能会对同一对象创建多个引用。由于单例只创建一个对象,因此这种情况下会对同一个对象创建多个引用。
● 所有依赖于全局变量的类都会由于一个类的改变而紧密耦合为全局数据,从而可能在无意中影响另一个类。

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

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

相关文章

基于算能的国产AI边缘计算盒子8核心A53丨17.6Tops算力

边缘计算盒子 8核心A53丨17.6Tops算力 ● 可提供17.6TOPS&#xff08;INT8&#xff09;的峰值计算能力、2.2TFLOPS&#xff08;FP32&#xff09;的高精度算力&#xff0c;单芯片最高支持32路H.264 & H.265的实时解码能力。 ● 适配Caffe/TensorFlow/MxNet/PyTorch/ ONNX/…

使用Plex结合cpolar搭建本地私人媒体站并实现远程访问

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特别是各…

Spring Initial 脚手架国内镜像地址

官方的脚手架下载太慢了&#xff0c;并且现在没有了Java8的选项&#xff0c;所以找到国内的脚手架镜像地址&#xff0c;推荐给大家。 首先说官方的脚手架 官方的脚手架地址为&#xff1a; https://start.spring.io/ 但是可以看到&#xff0c;并没有了Java8的选项。 所以推荐…

线程池(Linux +C/C++)

参考 手写线程池 - C语言版 | 爱编程的大丙 (subingwen.cn) 1.为什么需要线程池&#xff1f; 1&#xff09;线程问题&#xff1a; &#xff08;1&#xff09;如果只使用线程创建函数&#xff0c;在不断有新的任务进来的时候&#xff0c;需要不断的创建任务&#xff1b;任务在…

【已解决】为什么Word文档里有部分内容无法编辑?

小伙伴们是否遇到过这样的情况&#xff0c;打开Word文档进行编辑&#xff0c;发现部分内容可正常编辑&#xff0c;另外一部分内容却无法编辑。这是怎么回事&#xff0c;又要如何解决呢&#xff1f; 出现以上情况&#xff0c;一般是Word文档被设置了“限制保护”&#xff0c;使…

外包干了4年,技术退步太明显了。。。。。

先说一下自己的情况&#xff0c;本科生生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测…

PLC通过485Modbus转Profinet网关与温控表通讯在发酵罐的应用

前提&#xff1a;在自动化控制系统中&#xff0c;PLC通常需要和各种设备进行数据通讯&#xff0c;其中就包括温控表。而这些设备之间的通讯常常需要通过485Modbus转Profinet网关&#xff08;XD-MDPN100&#xff09;来实现。 方案&#xff1a;在一些应用场合中&#xff0c;Profi…

【C语言】扫雷小游戏初学者版

成功的秘诀就是每天都比别人多努力一点。 今天给大家带来一款非常经典的小游戏——扫雷的实现和讲解 这里是目录 前言整体框架1.打印菜单2.创建二维数组3.初始化棋盘4.打印棋盘5.布置棋盘中的雷6.排查雷和统计雷总体代码test.cgame.cgame.h 进阶&#xff08;递归展开&#xff0…

OpenLayer库的学习入门总结

前言&#xff1a; 作者跟随视频学习ol库的调用与功能实现&#xff0c;进行初步总结与回顾。 声明&#xff1a;参考新中地的文档&#xff0c;进行作者日后复习再次学习的简化。 1、WebGIS简介 GIS的核心概念 GIS&#xff08;Geographic Information System&#xff09;是一…

项目demo —— GPT 聊天机器人

本文介绍我的开源项目 TelegramChatBot&#xff0c;这是一个基于 OpenAI GPT API 开发的 telegram 机器人&#xff0c;具有多模态交互能力&#xff0c;求 star&#xff01;感谢大家&#xff01;在 telegram jokerController_bot 立即体验&#xff01;欢迎对 GPT 应用开发或对 t…

[cocos creator]EditBox,editing-return事件,清空输入框

需求&#xff1a; 监听EditBox&#xff0c;editing-return 回车事件&#xff0c;在输入框内点击回车后&#xff0c;发送内容&#xff0c;并清空输入框 问题&#xff1a; 设置node.getComponent(EditBox).string ; 没有效果 解决办法&#xff1a; //设置string 为空 this.v…

Linux入门攻坚——7、磁盘管理——文件系统挂载管理及RAID、LVM

已经安装文件系统的分区需要经过挂载才能使用。 一切文件系统的使用都是从根开始&#xff0c;根是文件系统的起始点。 计算机启动过程&#xff1a;加电自检——bootloader——kernel——rootfs——/sbin/init kernel第一步要加载根系统。 将额外文件系统与根文件系统某现存的…

Selenium自动化测试:通过cookie绕过验证码的操作

验证码的处理 对于web应用&#xff0c;很多地方比如登录、发帖都需要输入验证码&#xff0c;类型也多种多样&#xff1b;登录/核心操作过程中&#xff0c;系统会产生随机的验证码图片&#xff0c;进行验证才能进行后续操作 ​解决验证码的方法如下&#xff1a; 1、开发做个万…

Ubuntu20.04使用SVN(Rabbitvcs)

原文&#xff1a;https://blog.csdn.net/u014552102/article/details/129914787 1.安装Rabbitvcs sudo apt-get install rabbitvcs-nautilus sudo reboot 安装完后&#xff0c;选中一个文件夹右键&#xff0c;即可看到相关操作&#xff0c;没有的可以重启一下。 2.添加这个p…

数字化转型失败率为什么这么高?

引言 数字化转型已成为当今商业环境中的重要议题。它指的是企业通过采用数字技术&#xff0c;对业务流程、文化和客户体验进行全面变革&#xff0c;以适应数字化时代的需求和趋势。 然而&#xff0c;尽管数字化转型的重要性日益凸显&#xff0c;但令人担忧的是&#xff0c;许多…

C++ 红黑树的封装

一.map/set的封装 在实现了红黑树的部分功能后&#xff0c;我们可以便可以将红黑树作为底层结构来封装map 和 set &#xff0c;但是问题也随之而来。我们都知道map是k-v的数据模型&#xff0c;而set是k的数据模型&#xff0c;我们难道要去使用两棵红黑树来封装吗&#xff1f;显…

【jupyter notebook中插件 nbextensions 安装失败分析与解决方法】

文章目录 问题描述分析与解决总结 问题描述 一开始在安装 notebook 中的插件 nbextensions 时根本没有注意到版本的适配问题&#xff0c;都是进行默认的安装&#xff0c;结果安装是最新版本的 notebook7.x&#xff0c;恰好 notebook7.x 版本不再适应插件 nbextensions&#xf…

降本增笑?滴滴史上最严重服务故障,裁员真不能裁测试

2023 年 11 月 27 日晚间&#xff0c;滴滴因系统故障导致 App 服务异常&#xff0c;不显示定位且无法打车。11 月 27 日晚&#xff0c;滴滴出行进行了回复&#xff1a;非常抱歉&#xff0c;由于系统故障。 2023 年 11 月 28 日早间&#xff0c;滴滴出行消息称&#xff0c;网约…

在高德地图SDK上加载五层十五级瓦片的方法

目录 前言实现思路加载高德SDK,显示地图加载GroundOverlay类加载五层十五级瓦片清除瓦片总结前言 因为项目需求,需要在高德地图上加载五层十五级瓦片。这八竿子打不着的结合,着实没有思路。好在高德地图SDK提供了一个加载地表覆盖物的接口(GroundOverlay),这就为加载五层…

antv x6填坑指南: 部分节点拖拽和操作撤销重做不生效问题、使用Stencil过滤时过滤后分组的显示高度无法根据过滤节点自适应问题

问题1. 部分分组中节点拖拽添加或操作后撤销重做操作不生效。 前提&#xff1a;使用Stencil插件&#xff0c;创建画布侧边栏的 UI 组件&#xff0c;同时使用其分组、折叠能力。分组包含固定分组、后台接口获取的动态分组和组件。 //固定分组初始化 initStencil (graph, stenc…