什么是单例模式?为什么要用单例模式?实现的几种方式?
Python 中的单例模式
单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
【单例模式含义】
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
【采用单例模式动机、原因】
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
【单例模式优缺点】
【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用
单例模式的简单理解
1 单例模式 只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等
2 单例的缺点 就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
用单例模式,就是在适用其优点的状态下使用
在 Python 中,我们可以用多种方法来实现单例模式:
· 使用模块
· 使用 __new__
· 使用装饰器(decorator)
· 使用元类(metaclass)
使用模块
其实,Python的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
1 2 3 4 5 6 |
# mysingleton.py classMy_Singleton(object): def foo(self): pass my_singleton=My_Singleton() |
将上面的代码保存在文件 mysingleton.py
中,然后这样使用:
1 2 3 |
from mysingleton import my_singleton my_singleton.foo() |
使用 __new__
为了使类只能出现一个实例,我们可以使用 __new__
来控制实例的创建过程,代码如下:
1 2 3 4 5 6 7 8 9 |
classSingleton(object): _instance=None def __new__(cls,*args,**kw): ifnotcls._instance: cls._instance=super(Singleton,cls).__new__(cls,*args,**kw) returncls._instance classMyClass(Singleton): a=1 |
在上面的代码中,我们将类的实例和一个类变量 _instance
关联起来,如果 cls._instance
为 None 则创建实例,否则直接返回 cls._instance
。
执行情况如下:
1 2 3 4 5 6 7 8 |
>>>one=MyClass() >>>two=MyClass() >>>one==two True >>>one istwo True >>>id(one),id(two) (4303862608,4303862608) |
使用装饰器
我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from functools import wraps def singleton(cls): instances={} @wraps(cls) def getinstance(*args,**kw): ifcls notininstances: instances[cls]=cls(*args,**kw) returninstances[cls] returngetinstance @singleton classMyClass(object): a=1 |
在上面,我们定义了一个装饰器 singleton
,它返回了一个内部函数 getinstance
,该函数会判断某个类是否在字典 instances
中,如果不存在,则会将 cls
作为 key,cls(*args, **kw)
作为 value 存到 instances
中,否则,直接返回 instances[cls]
。
使用 metaclass
元类(metaclass)可以控制类的创建过程,它主要做三件事:
· 拦截类的创建
· 修改类的定义
· 返回修改后的类
使用元类实现单例模式的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
classSingleton(type): _instances={} def __call__(cls,*args,**kwargs): ifcls notincls._instances: cls._instances[cls]=super(Singleton,cls).__call__(*args,**kwargs) returncls._instances[cls] # Python2 classMyClass(object): __metaclass__=Singleton # Python3 # class MyClass(metaclass=Singleton): # pass |
小结
· Python 的模块是天然的单例模式,这在大部分情况下应该是够用的,当然,我们也可以使用装饰器、元类等方法
本文由 funhacks 发表于个人博客,采用 Creative Commons BY-NC-ND 4.0(自由转载-保持署名-非商用-禁止演绎)协议发布。
非商业转载请注明作者及出处。商业转载请联系作者本人。
本文标题为: Python 中的单例模式
本文链接为: https://funhacks.net/2017/01/…
什么是单例模式?为什么要用单例模式?实现的几种方式?相关推荐
- IOS swift项目的单例模式.swift5以后的单例模式
IOS swift项目的单例模式.swift5以后的单例模式 不能继承NSObject 第一种写法,最简单 class SoundTools{static let sharedInstance = S ...
- python实现单例模式的几种方式_基于Python中单例模式的几种实现方式及优化详解...
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- python实现单例模式的三种方式及相关知识解释
python实现单例模式的三种方式及相关知识解释 模块模式 装饰器模式 父类重写new继承 单例模式作为最常用的设计模式,在面试中很可能遇到要求手写.从最近的学习python的经验而言,singlet ...
- 单例模式在JavaScript与TypeScript中的几种设计方式
1.单例模式 为什么要使用单例模式? 在某些情况下,在处理多个模块的数据时,他们没有什么联系,但是我们想要用一个公共的部分来进行储存状态或者数据. 为了保证这些模块之间能够稳定统一,那就要求这个公共部 ...
- 设计模式-单例模式-注册式单例模式-枚举式单例模式和容器式单例模式在Java中的使用示例
场景 设计模式-单例模式-饿汉式单例模式.懒汉式单例模式.静态内部类在Java中的使用示例: 设计模式-单例模式-饿汉式单例模式.懒汉式单例模式.静态内部类在Java中的使用示例_霸道流氓气质的博客- ...
- java利用单例模式存储参数_java单例模式使用及注意事项
strtok函数实际上是要把第一个参数的字符串进行修改的.因为这个原因这个字符串的存储位置就不能是只读的, 也就是说不能存放在常量区.在使用char* aa ="abcdefg"; ...
- android中的单例模式,Android中的单例模式
定义: 单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 使用场景: 确保某一个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一 ...
- python 空对象模式_Python 单例模式(3种方式)
# 单例模式: # 实现目的:实例化多次,得到的实例是同一个,就是同一个对象,同一个名称空间(更加节省空间) ####################################方式一:在类内部定 ...
- 【学亮说】Java实现单例模式的8种方式(你真的搞懂单例模式了吗?)
第一种:饿汉式单例模式 package com.zhangxueliang.dp.sigleton;/*** 饿汉式单例模式* * @Author:Zhang Xueliang* * @Date:20 ...
- python单例模式数据库连接池_Python实现单例模式的四种方式
# 单例模式实现方式一:类方法import settingsclass MySQL:__instance=Nonedef __init__(self, ip, port):self.ip = ips ...
最新文章
- AMI:加密的机器映像。卷
- 《架构之美》阅读笔记一
- 关于mobile中datagrid的使用
- jquery批量删除
- 使用 Vue.js 和 Chart.js 制作绚丽多彩的图表
- 读DS18B20序列号(c语言)
- Spring入门学习手册 2:怎么用注解来DI/IOC
- OSChina 周日乱弹 —— 在宅的路上越走越远。。。
- 【ICLR 2018】模型集成的TRPO算法【附代码】
- 深入理解vsto,开发word插件的利器
- (有理数类 )创建一个名为Rational的类,进行分数运算。
- Python 数据处理工具 Pandas(上)
- javaSE探赜索隐五<异常>
- codeforces 1598 A
- 酷炫的数据可视化大屏来了!满足你99%大屏需求
- python矩阵变成图片_Python图片转换成矩阵,矩阵数据转换成图片
- linux开机自启任务和定时任务
- Andersen Global在莫桑比克扩张业务
- Netgear R6220桥接组网设置
- 版本管理之SVN实践教程:基础篇(5):提交/解决冲突/回退/确认