5种Python单例模式的实现方式


Posted in Python onJanuary 14, 2016

本文为大家分享了Python创建单例模式的5种常用方法,供大家参考,具体内容如下

所谓单例,是指一个类的实例从始至终只能被创建一次。
方法1:
如果想使得某个类从始至终最多只有一个实例,使用__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('apple')  
  b=A('banana')
  print id(a),a.s
  print id(b),b.s

结果:
29922256 banana
29922256 banana
通过__new__方法,将类的实例在创建的时候绑定到类属性_inst上。如果cls._inst为None,说明类还未实例化,实例化并将实例绑定到cls._inst,以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton派生子类的时候,不要重载__new__。
方法2:
有时候我们并不关心生成的实例是否具有同一id,而只关心其状态和行为方式。我们可以允许许多个实例被创建,但所有的实例都共享状态和行为方式:

class Borg(object):
  _shared_state={}
  def __new__(cls,*args,**kwargs):
    obj=super(Borg,cls).__new__(cls,*args,**kwargs)
    obj.__dict__=cls._shared_state
    return obj

将所有实例的__dict__指向同一个字典,这样实例就共享相同的方法和属性。对任何实例的名字属性的设置,无论是在__init__中修改还是直接修改,所有的实例都会受到影响。不过实例的id是不同的。要保证类实例能共享属性,但不和子类共享,注意使用cls._shared_state,而不是Borg._shared_state。
因为实例是不同的id,所以每个实例都可以做字典的key:

if __name__=='__main__':
  class Example(Borg):
    pass
  a=Example()
  b=Example()
  c=Example()
  adict={}
  j=0
  for i in a,b,c:
    adict[i]=j
    j+=1
  for i in a,b,c:
    print adict[i]

结果:
0
1
2
如果这种行为不是你想要的,可以为Borg类添加__eq__和__hash__方法,使其更接近于单例模式的行为:

class Borg(object):
  _shared_state={}
  def __new__(cls,*args,**kwargs):
    obj=super(Borg,cls).__new__(cls,*args,**kwargs)
    obj.__dict__=cls._shared_state
    return obj
  def __hash__(self):
    return 1
  def __eq__(self,other):
    try:
      return self.__dict__ is other.__dict__
    except:
      return False
if __name__=='__main__':
  class Example(Borg):
    pass
  a=Example()
  b=Example()
  c=Example()
  adict={}
  j=0
  for i in a,b,c:
    adict[i]=j
    j+=1
  for i in a,b,c:
    print adict[i]

结果:
2
2
2
所有的实例都能当一个key使用了。
方法3
当你编写一个类的时候,某种机制会使用类名字,基类元组,类字典来创建一个类对象。新型类中这种机制默认为type,而且这种机制是可编程的,称为元类__metaclass__ 。

class Singleton(type):
  def __init__(self,name,bases,class_dict):
    super(Singleton,self).__init__(name,bases,class_dict)
    self._instance=None
  def __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)

结果:
34248016 34248016
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):
    pass
  def __setattr__(self,name,value):
    if name in self.__dict__:
      raise self.ConstError
    self.__dict__[name]=value
  def __delattr__(self,name):
    if name in self.__dict__:
      raise self.ConstError
    raise 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单例模式的实现方式详细介绍,希望对大家的学习有所帮助。

Python 相关文章推荐
python网络编程学习笔记(五):socket的一些补充
Jun 09 Python
Python实现的生成自我描述脚本分享(很有意思的程序)
Jul 18 Python
利用python求解物理学中的双弹簧质能系统详解
Sep 29 Python
对python使用http、https代理的实例讲解
May 07 Python
详解python中的Turtle函数库
Nov 19 Python
Python 中使用 PyMySQL模块操作数据库的方法
Nov 10 Python
Python:二维列表下标互换方式(矩阵转置)
Dec 02 Python
利用 Python ElementTree 生成 xml的实例
Mar 06 Python
TensorFlow tf.nn.conv2d_transpose是怎样实现反卷积的
Apr 20 Python
Python 实现敏感目录扫描的示例代码
May 21 Python
使用pytorch 筛选出一定范围的值
Jun 28 Python
总结python多进程multiprocessing的相关知识
Jun 29 Python
Python2.x与Python3.x的区别
Jan 14 #Python
python Django模板的使用方法
Jan 14 #Python
Python数据类型学习笔记
Jan 13 #Python
python基础入门学习笔记(Python环境搭建)
Jan 13 #Python
详解python时间模块中的datetime模块
Jan 13 #Python
Python时间模块datetime、time、calendar的使用方法
Jan 13 #Python
基于Python实现文件大小输出
Jan 11 #Python
You might like
PHP开发负载均衡指南
2010/07/17 PHP
关于恒等于(===)和非恒等于(!==)
2007/08/20 Javascript
使Ext的Template可以解析二层的json数据的方法
2007/12/22 Javascript
javascript 显示当前系统时间代码
2009/12/28 Javascript
JS运动基础框架实例分析
2015/03/03 Javascript
jquery模拟alert的弹窗插件
2015/07/31 Javascript
AngularJS过滤器filter用法总结
2016/12/13 Javascript
[js高手之路]单例模式实现模态框的示例
2017/09/01 Javascript
ECMAScript6变量的解构赋值实例详解
2017/09/19 Javascript
Vue响应式原理深入解析及注意事项
2017/12/11 Javascript
详解Vue用cmd创建项目
2019/02/12 Javascript
Vue 自定义指令实现一键 Copy功能
2019/09/16 Javascript
[54:09]RNG vs Liquid 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
python基于xml parse实现解析cdatasection数据
2014/09/30 Python
Django实现简单分页功能的方法详解
2017/12/05 Python
pandas 将list切分后存入DataFrame中的实例
2018/07/03 Python
Pytorch Tensor的索引与切片例子
2019/08/18 Python
Python下应用opencv 实现人脸检测功能
2019/10/24 Python
python 穷举指定长度的密码例子
2020/04/02 Python
Python读取图像并显示灰度图的实现
2020/12/01 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
css3 伪元素和伪类选择器详解
2014/09/04 HTML / CSS
欧洲最大的婴幼儿服装及内衣公司:Petit Bateau(小帆船)
2016/08/16 全球购物
海外淘书首选:AbeBooks
2017/07/31 全球购物
董事长秘书岗位职责
2013/11/29 职场文书
触摸春天教学反思
2014/02/03 职场文书
市场营销专业毕业生求职信
2014/03/26 职场文书
计算机相关专业自荐信
2014/07/02 职场文书
2014年党的群众路线整改措施思想汇报
2014/10/12 职场文书
教师个人事迹材料
2014/12/17 职场文书
2015年度党员自我评价范文
2015/03/03 职场文书
保研推荐信范文
2015/03/25 职场文书
劳务派遣管理制度(样本)
2019/08/23 职场文书
node快速搭建后台的实现步骤
2022/02/18 NodeJs
vue.js 使用原生js实现轮播图
2022/04/26 Vue.js
Spring IOC容器Bean的作用域及生命周期实例
2022/05/30 Java/Android