python的单例模式详解

news/2025/1/11 12:44:01/

一、什么是单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
单例设计模式:
**目的:**让类创建的对象,在系统只执行唯一实例,即每一次执行类名.()返回的对象,内存地址是相同的,可以通过id(实例对象)来查看实例对象对应的内存空间地址。
应用场景: 音乐播放器、回收站对象、打印机对象…

二、通过装饰器实现单例模式

面试真题:
通过装饰器实现单例模式,只要任意一个类使用该装饰器装饰,
那么就会变成一个单例模式的类。
1.用函数方法实现:

def single(cls):cls.instance = Nonedef wrapper(*args, **kwargs):# 判断类是否有instance属性if not cls.instance:# 通过类创建对象,并保存为instance属性cls.instance = cls(*args, **kwargs)# 返回对象return cls.instancereturn wrapper
@single  # A = single(A)
class A:pass
a1 = A()
a2 = A()
print(a1, a2)

运行结果:

<__main__.A object at 0x000001F125DE2D60> <__main__.A object at 0x000001F125DE2D60>

2.通过类来实现:

class single1:def __init__(self, cls):self.cls = clsself.cls.instance = Nonedef __call__(self, *args, **kwargs):if not self.cls.instance:self.cls.instance = self.cls(*args, **kwargs)return self.cls.instance
@single1  
class B:pass
b1 = B()
b2 = B()
print(b1, b2)        

运行结果:

<__main__.B object at 0x000001F125DE2DC0> <__main__.B object at 0x000001F125DE2DC0>

三、基于基于__new__方法实现

__new__方法:
使用类名()创建对象时,python的解释器首先会调用__new__方法为对象分配空间,然后在执行__init__初始话实例对象。

object提供的__new__静态方法,主要有2个作用:

  1. 在内存中为对象分配空间
  2. 返回对象的引用

Python解释器获取对象的引用后,将引用作为第一个参数,传递给__init__方法
注意点:
重写__new__方法一定要return super().new(cls), 否则python解释器得不到分配空间引用,就不会调用对象的初始化
__new__是一个静态方法,在调用时需要主动传递cls函数。

代码实现:

class A(object):__instance = Nonedef __new__(cls, *args, **kwargs):if cls.__instance is None:cls.__instance = super().__new__(cls)return cls.__instanceelse:return cls.__instancea1 = A()
a2 = A()
print("a1的id为:", id(a1))
print("a2的id为:", id(a2))
print("a1 is a2:", a1 is a2)
print(a1)
print(a2)

运行结果:

a1的id: 2168943480688
a2的id: 2168943480688
a1 is a2: True
<__main__.A object at 0x000001F8FF1B0F70>
<__main__.A object at 0x000001F8FF1B0F70>

解析如下:
目的: 让类创建的对象,在系统中只有唯一的一个实例
流程:
定义一个类属性,初始值是None, 用于记录单例对象的引用。
重写__new__方法
如果类属性is None,调用父类方法分配空间,并在类属性中记录结果
返回类属性中记录的对象引用。


http://www.ppmy.cn/news/335875.html

相关文章

BMW Series3/5/7

3-Series 第一代&#xff0c;E21&#xff0c;1975。有些许粗糙&#xff0c;过于简单。 第二代&#xff0c;E30&#xff0c;1984。最喜欢的一代&#xff0c;外观新颖大气。 第三代&#xff0c;E36&#xff0c;1991。外观开始变得有些现代了&#xff0c;介于复古和现代之间的产物…

2013年杰森·斯坦森动作《蜂鸟》720p.BD中英双字幕

2013年杰森斯坦森动作《蜂鸟》720p.BD中英双字幕 发布时间&#xff1a;2013-07-11 ◎译  名 蜂鸟 ◎片  名 Redemption/Hummingbird ◎年  代 2013 ◎国  家 美国/英国 ◎类  别 动作/惊悚 ◎语  言 英语 ◎字  幕 中英双字幕 ◎IMDB评分 6.3/10 from 4…

python引用计数的原理

垃圾回收机制&#xff1a; python的垃圾回收采用的是 引用计数机制为主和 分代回收机制为辅的 结合机制&#xff0c;当对象的引用计数变为0时&#xff0c;对象将被销毁&#xff0c;除了解释器默认创建的对象外&#xff08;默认对象的引用计数永远不会变成0&#xff09; python关…

vue的provide与inject如何使用?能否实现双向绑定?

provide与inject 1. provide与inject用法2.使用示例3.provide与inject实现双向绑定 vue 组件间的通信方式有很多种&#xff0c;所以使用时需要考虑哪种方式是最合适的。若仅仅是简单的隔代组件通信&#xff0c;我认为使用 provide与inject会更加方便。 1. provide与inject用法…

I O 流

Stream流的三类方法 获取Stream流 创建一条流水线&#xff0c;并把数据放到流水线上准备进行操作中间方法 流水线上的操作 一次操作完毕之后&#xff0c;还可以继续进行其他操作。终结方法 一个Stream流只能有一个终结方法 是流水线上的最后一个操作 Stream流的获取方法 单列…

Day12 面向对象的三大特性

面向对象的三大特征&#xff1a;封装、继承、多态 1、封装 (1)类的封装特征 隐藏对象的属性和实现细节&#xff0c;只对外提供必要的方法。 通过“私有属性、私有方法”的方式&#xff0c;实现“封装”。Python 追求简洁的语法 class game:def __init__(self,type):self.ty…

叫醒我的不是闹钟,是梦想

转眼间就来到兄弟连一个多月了&#xff0c;在兄弟连呆过的兄弟相信大家都有这种体会&#xff0c;每天撸代码到深夜&#xff0c;早上就要七八点多就要起床。相信大家已经习惯了这种生活。 虽睡眠虽然不充足但我从没有一次迟到&#xff0c;而且我从没有设闹钟的习惯&#xff0c;因…

Python之类和对象【三】---继承(2.1-多继承,多重继承,多态)

文章目录 前言一、多继承二、多重继承三、多态总结 前言 记录多继承&#xff0c;多态的含义&#xff0c;理清思路。 一、多继承 含义&#xff1a;一个子类可以继承多个父类。 class 子类(父类1, 父类2.....): pass 一般这种情况&#xff0c;父类之间是没有什么关联&…