单例模式(Singleton Pattern)是一种常用的软件设计模式,是指一个类的实例从始至终只能被创建一次,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

主要优点:

1、提供了对唯一实例的受控访问。

2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

3、允许可变数目的实例。

主要缺点:

1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

2、单例类的职责过重,在一定程度上违背了“单一职责原则”。

3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

适用场景

在以下情况下可以考虑使用单例模式:

  • (1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。

  • (2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

实现某个类只有一个实例的途径:

1,让一个全局变量使得一个对象被访问,但是他不能防止外部实例化多个对象。

2,让类自身保存他的唯一实例,这个类可以保证没有其他实例可以被创建。

多线程时的单例模式:加锁-双重锁定

饿汉式单例类:在类被加载时就将自己实例化(静态初始化)。其优点是躲避了多线程访问的安全性问题,缺点是提前占用系统资源。

懒汉式单例类:在第一次被引用时,才将自己实例化。避免开始时占用系统资源,但是有多线程访问安全性问题。

方法1:使用__new__方法

如果想使得某个类从始至终最多只有一个实例,使用__new__方法会很简单。Python中类是通过__new__来创建实例的:

class Singleton(object):def __new__(cls,*args,**kwargs):if not hasattr(cls,'_inst'):cls._inst=super(Singleton,cls).__new__(cls,*args,**kwargs)return cls._inst
if __name__=='__main__':class A(Singleton):def __init__(self,s):self.s=s   a=A('java')  b=A('python')print id(a),a.sprint id(b),b.s

结果:

9621235 python
9921235 python

通过__new__方法,将类的实例在创建的时候绑定到类属性_inst上。如果cls._inst为None,说明类还未实例化,实例化并将实例绑定到cls.inst,以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton派生子类的时候,不要重载__new_。

方法2:使用装饰器

我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:

from functools import wraps
def singleton(cls):instances = {}@wraps(cls)def getinstance(*args, **kw):if cls not in instances:instances[cls] = cls(*args, **kw)return instances[cls]return getinstance
@singleton
class MyClass(object):a = 1

在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]。

方法3:使用元类(metaclass)

当你编写一个类的时候,某种机制会使用类名字,基类元组,类字典来创建一个类对象。新型类中这种机制默认为type,而且这种机制是可编程的,称为元类__metaclass__ 。

class Singleton(type):def __init__(self,name,bases,class_dict):super(Singleton,self).__init__(name,bases,class_dict)self._instance=Nonedef __call__(self,*args,**kwargs):if self._instance is None:self._instance=super(Singleton,self).__call__(*args,**kwargs)return self._instance
if __name__=='__main__':class A(object):__metaclass__=Singleton    a=A()b=A()print id(a),id(b)

结果:

43645654 43645654

id是相同的。

例子中我们构造了一个Singleton元类,并使用__call__方法使其能够模拟函数的行为。构造类A时,将其元类设为Singleton,那么创建类对象A时,行为发生如下:

A=Singleton(name,bases,class_dict),A其实为Singleton类的一个实例。

创建A的实例时,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),这样就将A的所有实例都指向了A的属性_instance上,这种方法与方法1其实是相同的。

方法4:使用模块

python中的模块module在程序中只被加载一次,本身就是单例的。可以直接写一个模块,将你需要的方法和属性,写在模块中当做函数和模块作用域的全局变量即可,根本不需要写类。

而且还有一些综合模块和类的优点的方法:

class _singleton(object):class ConstError(TypeError):passdef __setattr__(self,name,value):if name in self.__dict__:raise self.ConstErrorself.__dict__[name]=valuedef __delattr__(self,name):if name in self.__dict__:raise self.ConstErrorraise NameError
import sys
sys.modules[__name__]=_singleton()

python并不会对sys.modules进行检查以确保他们是模块对象,我们利用这一点将模块绑定向一个类对象,而且以后都会绑定向同一个对象了。

将代码存放在single.py中:

>>> import single
>>> single.a=1
>>> single.a=2
ConstError
>>> del single.a
ConstError

方法5:名字绑定法

最简单的方法:

class singleton(object):pass
singleton=singleton()

将名字singleton绑定到实例上,singleton就是它自己类的唯一对象了。

Python创建单例模式的5种方法相关推荐

  1. Python创建多线程的三种方法

    Python创建多线程的三种方法 thread模块函数式创建线程 继承threading类创建多线程 threading模块函数式创建线程 使用总结 thread模块函数式创建线程 调用thread模 ...

  2. python实现单例模式的三种方法

    单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 其目 ...

  3. python创建字典的两种方法要求键星期一到星期天_Python3笔记019 - 4.4 字典

    第4章 序列的应用 4.1 序列 4.2 列表 4.3 元组 4.4 字典 4.5 集合 4.6 列表.元组.字典.集合的区别 python的数据类型分为:空类型.布尔类型.数字类型.字节类型.字符串 ...

  4. python process 函数_Python Process创建进程的2种方法详解

    前面介绍了使用 os.fork() 函数实现多进程编程,该方法最明显的缺陷就是不适用于 Windows 系统.本节将介绍一种支持 Python 在 Windows 平台上创建新进程的方法. Pytho ...

  5. python实现单例模式的几种方式_基于Python中单例模式的几种实现方式及优化详解...

    单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...

  6. python实现单例模式的三种方式及相关知识解释

    python实现单例模式的三种方式及相关知识解释 模块模式 装饰器模式 父类重写new继承 单例模式作为最常用的设计模式,在面试中很可能遇到要求手写.从最近的学习python的经验而言,singlet ...

  7. 基础必备 | Python处理文件系统的10种方法

    作者 | Jeff Hale 译者 | 风车云马:责编 | Jane,Rachel 出品 | Python大本营(ID:pythonnews) [导读]在编写一些Python程序的时候,我们常常需要与 ...

  8. python调用cmd命令释放端口_详解python调用cmd命令三种方法

    目前我使用到的python中执行cmd的方式有三种 使用os.system("cmd") 该方法在调用完shell脚本后,返回一个16位的二进制数,低位为杀死所调用脚本的信号号码, ...

  9. 深度盘点:Python 变量类型转换的 6 种方法

    大家好,今天我来给大家介绍 Python 变量类型转换的 6 种方法.梳理不易,喜欢记得点赞.收藏.关注. [注]完整版代码.数据.技术交流,文末获取 一.变量类型及转换 对于变量的数据类型而言,Pa ...

最新文章

  1. 让表单文本框只读不可编辑的方法
  2. hdfs中8031是什么端口号_在宿主机如何访问docker中hadoop的hdfs:ip:9000啊, 端口映射出来啊...
  3. 【CF1311E】Construct the Binary Tree【增量构造】【复杂度证明】
  4. [FPGA][DE0] Qsys 加入 FLASH 記憶體 方法及步驟
  5. web Api 返回json 的两种方式
  6. Jsp+Servlet+Mysql实现的在线鲜花商城源码
  7. 从C# 3.0到F#
  8. centos6 与 7 其中的一些区别
  9. idea启动日志在哪里_艹,我的日志被Intellij IDEA 控制台给“吃”了!
  10. java Relative Path and absolute
  11. SENT协议学习总结
  12. 【乌拉喵.教程】TestBench仿真给输出脚赋值引起的问题
  13. ChartControl柱状图指定每一个柱子的颜色
  14. python统计大写辅音字母_大写
  15. 计算机网络的三大功能,计算机网络主要功能
  16. 【css】巧用border制作三角形
  17. 小程序开发API之监听加速计wx.startAccelerometer
  18. 记录-gitlab自动部署-git拉取代码失败构建失败 + linux系统升级git(yum安装 + 源码安装)
  19. u盘文件删去了怎么样找得回来
  20. 【转载】关于重定向RedirectAttributes的用法

热门文章

  1. LUA Metatables
  2. CentosMySQL5.6安装方法
  3. day17-jdbc 6.Connection介绍
  4. 5.js模式-职责链模式
  5. wpf中把按钮变成圆角
  6. Lua的继承(利用setmetatable)
  7. Silverlight3 Tools Download link
  8. java构造函数调用其他程序的顺序_java初始化构造函数调用顺序
  9. 第27章:MongoDB-索引--唯一索引
  10. 设计模式(三)--观察者模式