(三)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 = None
    def __init__(self):
        if not Singleton._instance:
            print("类已初始化,但实例未创建!")
        else:
            print("实例已创建", self.getInstance())
    @classmethod
    def 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 = x
        self.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 = None
    def 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.mfbz.cn/a/213894.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode刷题---反转链表

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏&#xff1a;http://t.csdnimg.cn/ZxuNL http://t.csdnimg.cn/c9twt 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回溯算法&#xff0c;所以下面题目主要也是这些算法做的 我讲述…

MDETR 论文报告

MDETR - Modulated Detection for End-to-End Multi-Modal Understanding MDETR - Modulated Detection for End-to-End Multi-Modal Understanding发现问题主要贡献和创新点主要方法和技术MDETR 的架构损失函数1. 框预测损失2. 软标记预测损失3. 对比对齐损失4. 总损失 实验和…

Linux网络之连接跟踪 conntrack

一 Linux网络之连接跟踪 conntrack k8s 有关conntrack的分析 ① 什么是连接跟踪 netfilter连接跟踪 conntrack 详述 思考&#xff1a;连接跟踪模块会对哪些协议进行跟踪?TCP、UDP、ICMP、DCCP、SCTP、GRE ② 为什么需要连接跟踪 没有连接跟踪有很多问题是不好解决的&a…

C语言-内存分配

内存分配 1. 引入 int nums[10] {0}; //对int len 10; int nums[len] {0}; //错是因为系统的内存分配原则导致的2. 概述 在程序运行时&#xff0c;系统为了 更好的管理进程中的内存&#xff0c;所以有了 内存分配机制。 分配原则&#xff1a; 2.1 静态分配 静态分配原…

解决top-k问题--堆排序

目录 TOP-K问题 堆排序 考虑以下情况&#xff1a; 1.在n个数里面找最大的一个数 2.在n个数里面找最大的两个数 3.在n个数中求前k大的数 为什么不用大根堆呢&#xff1f; 代码 时间复杂度 TOP-K问题 即求数据结合中前K个最大的元素或者最小的元素&#xff0c;一般情况下数…

使用Redis构建任务队列

文章目录 第1关&#xff1a;先进先出任务队列第2关&#xff1a;优先级任务队列第3关&#xff1a;定时任务队列 第1关&#xff1a;先进先出任务队列 编程要求 在Begin-End区域编写 add_task(task_name) 函数&#xff0c;实现将任务加入队列的功能&#xff0c;具体参数与要求如下…

论文阅读——Loss odyssey in medical image segmentation

Loss odyssey in medical image segmentation github&#xff1a;https://github.com/JunMa11/SegLossOdyssey 这篇文章回顾了医学图像分割中的20种不同的损失函数&#xff0c;旨在回答&#xff1a;对于医学图像分割任务&#xff0c;我们应该选择哪种损失函数&#xff1f; 首…

使用 Kettle 完成数据 ETL

文章目录 使用 Kettle 完成数据 ETL数据清洗数据处理 使用 Kettle 完成数据 ETL 现在我们有一份网站的日志数据集&#xff0c;准备使用Kettle进行数据ETL。先将数据集加载到Hadoop集群中&#xff0c;然后对数据进行清洗&#xff0c;最后加载到Hive中。 在本地新建一个数据集文…

解决vscode中html部分无法嵌套注释

不管是React项目还是Vue项目&#xff0c;相信你一定遇到过同样的问题&#xff0c;如果想要注释的结构内部也存在注释&#xff0c;那么编译器会报以下问题 使用 HTML-Comment 这个插件即可解决问题 选中需要注释的区域并根据系统输入快捷键&#xff0c;可以发现就算嵌套了注释…

【论文解读】角色动画的一致可控的图像到视频合成

论文&#xff1a;https://arxiv.org/pdf/2311.17117.pdf 代码&#xff1a;https://github.com/HumanAIGC/AnimateAnyone 图片解释&#xff1a;给定参考图像&#xff08;每组中最左边的图像&#xff09;的一致且可控的角色动画结果。我们的方法能够对任意角色进行动画处理&#…

人工智能原理复习--不确定推理

文章目录 上一篇不确定推理概述主观Bayes(贝叶斯)方法可信度方法证据理论下一篇 上一篇 人工智能原理复习–确定性推理 不确定推理概述 常识具有不确定性。 常识往往对环境有极强的依存性。 其中已知事实和知识是构成推理的两个基本要素&#xff0c;不确定性可以理解为在缺…

Makefile初学之谜之隐式规则

刚开始学习Make教程&#xff1a;https://makefiletutorial.vercel.app/#/docs/fancy-rules&#xff0c;里面有个sample: objects foo.o bar.o all.o all: $(objects)# These files compile via implicit rules foo.o: foo.c bar.o: bar.c all.o: all.call.c:echo "int…

python--自动化办公(Word)

python自动化办公之—Word python-docx库 1、安装python-docx库 pip install python-docx2、基本语法 1、打开文档 document Document() 2、加入标题 document.add_heading(总标题,0) document.add_heading(⼀级标题,1) document.add_heading(⼆级标题,2) 3、添加文本 para…

Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂)

目录 一、前言 二、通过类型来获取Bean 0.总述&#xff08;重要&#xff09; : 1.基本介绍 : 2.应用实例 : 三、通过指定构造器为Bean注入属性 1.基本介绍 : 2.应用实例 : 四、通过p命名空间为Bean注入属性 1.基本介绍 : 2.应用实例 : 五、通过ref引用实现Bean的相…

手机也能“敲”代码?

除了PC个人电脑外&#xff0c;很多电子产品也可以实现代码的编辑&#xff0c;比如智能手机。现在主流的手机操作系统只有两种&#xff0c;一种是大部分手机厂商选择的安卓系统&#xff0c;另外一种是苹果公司独创的ios操作系统。而Android系统是基于Linux开发的专属于移动设备的…

【Leetcode题单】(01 数组篇)刷题关键点总结03【数组的改变、移动】

【Leetcode题单】&#xff08;01 数组篇&#xff09;刷题关键点总结03【数组的改变、移动】&#xff08;3题&#xff09; 数组的改变、移动453. 最小操作次数使数组元素相等 Medium665. 非递减数列 Medium283. 移动零 Easy 大家好&#xff0c;这里是新开的LeetCode刷题系列&…

Java数据结构之《构造哈夫曼树》题目

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等(偏难理解)的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题…

【蓝桥杯】翻硬币

翻硬币 思路&#xff1a; 其实有点贪心的意思&#xff0c;依次比较&#xff0c;不同就1&#xff0c;然后修改自己的字符串和下一个的字符串&#xff0c;再匹配。 #include<iostream> #include<string> using namespace std;string now,res;int main(void) {cin&g…

MQ - 消息系统

消息系统 1、消息系统的演变 在大型系统中&#xff0c;会需要和很多子系统做交互&#xff0c;也需要消息传递&#xff0c;在诸如此类系统中&#xff0c;你会找到源系统&#xff08;消息发送方&#xff09;和 目的系统&#xff08;消息接收方&#xff09;。为了在这样的消息系…

java高校实验室排课学生考勤系统springboot+vue

随着各高校办学规模的迅速扩大,学科专业的不断拓宽,传统的实验教学和实验室管理方法已经不能适应学校管理的要求,特别是化学实验室的管理,化学实验室仪器药品繁杂多样,管理任务繁重,目前主要使用人工记录方法管理,使用不便,效率低下,而且容易疏漏.时间一长将产生大量的文件和数…
最新文章