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

本文为大家分享了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._instif __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 Falseif __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._instanceif __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 NameErrorimport syssys.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):  passsingleton=singleton()

登录后复制

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

以上就是Python单例模式的实现方式详细介绍,希望对大家的学习有所帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2535288.html

(0)
上一篇 2025年3月5日 22:28:35
下一篇 2025年3月5日 22:28:58

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • python结合API实现即时天气信息

    python结合api实现即时天气信息 import urllib.requestimport urllib.parseimport json “”” 利用“最美天气”抓取即时天气情况 http://www.zuimeitianqi.com…

    编程技术 2025年3月5日
    000
  • Python聊天室实例程序分享

    上一篇 我们学习了简单的python tcp socket 编程,通过分别写服务端和客户端的代码了解基本的 python socket 编程模型。本文再通过一个例子来加强一下对 socket 编程的理解。 一、聊天室程序需求我们要实现的是简…

    2025年3月5日
    200
  • 黑科技 Python脚本帮你找出微信上删除你好友的人

    相信大家在微信上一定被上面的这段话刷过屏,群发消息应该算是微信上流传最广的找到删除好友的方法了。但群发消息不仅仅会把通讯录里面所有的好友骚扰一遍,而且你还得挨个删除好几百个聊天记录,回复大家的疑问和鄙视。作为一个互联网从业者,除了群发消息就…

    2025年3月5日
    200
  • 详解Python Socket网络编程

    socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 socket 来完成通信的,例如我们每天浏览网页、qq 聊天、收发 email 等等。要解决网络…

    编程技术 2025年3月5日
    200
  • 星球大战与Python之间的那些事

    python与星球大战背后的工业光魔 提起Python语言,很多人会想起系统运维、Web开发等工作。很少有人会知道Python也能够用于电影视觉特效的制作,其中就包括了《星球大战》某些电影特效的制作。 星战之父乔治·卢卡斯于1975年创建了…

    2025年3月5日
    200
  • 菜鸟使用python实现正则检测密码合法性

    客户系统升级,要求用户密码符合一定的规则,即:包含大小写字母、数字、符号,长度不小于8,于是先用python写了个简单的测试程序: 在写解决方案前,列一下 python正则表达式中的特殊字符: ^          表示匹配的字符必须在最前…

    编程技术 2025年3月5日
    200
  • Python字符串特性及常用字符串方法的简单笔记

    单引号和双引号都能表示字符串。区别在于转义的时候。 如果懒得加转义字符,可以通过在字符串前面加上r。例如: print r’C:someame’ 登录后复制 通过在字符串里面添加反斜杠来不换行。 print “”” Usage: thing…

    编程技术 2025年3月5日
    200
  • Python实现控制台进度条功能

    本文实例讲述了python显示进度条的方法,是python程序设计中非常实用的技巧。分享给大家供大家参考。具体方法如下: 首先,进度条和一般的print区别在哪里呢? 答案就是print会输出一个,也就是换行符,这样光标移动到了下一行行首,…

    2025年3月5日
    200
  • python实现网站的模拟登录

    本文主要用python实现了对网站的模拟登录。通过自己构造post数据来用python实现登录过程。 当你要模拟登录一个网站时,首先要搞清楚网站的登录处理细节(发了什么样的数据,给谁发等…)。我是通过HTTPfox来抓取http…

    编程技术 2025年3月5日
    200
  • python访问mysql数据库的实现方法(2则示例)

    本文实例讲述了python访问mysql数据库的实现方法。分享给大家供大家参考,具体如下: 首先安装与Python版本匹配的MySQLdb 示例一 import MySQLdbconn=MySQLdb.connect(user=’root’…

    编程技术 2025年3月5日
    200

发表回复

登录后才能评论