所谓单例,是指一个类的实例从始至终只能被创建一次,,而且自行实例化并向整个系统提供这个实例。

方法1

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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

结果:

1

2

29922256 banana

29922256 banana

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

方法2:

有时候我们并不关心生成的实例是否具有同一id,而只关心其状态和行为方式。我们可以允许许多个实例被创建,但所有的实例都共享状态和行为方式:

1

2

3

4

5

6

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:

1

2

3

4

5

6

7

8

9

10

11

12

13

if __name__== '__main__':

class Example(Borg):

pass

a= Example()

b= Example()

c= Example()

adict= {}

j= 0

for iin a, b, c:

adict[i]= j

j+= 1

for iin a, b, c:

print adict[i]

结果:

1

2

3

0

1

2

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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 iin a, b, c:

adict[i]= j

j+= 1

for iin a, b, c:

print adict[i]

结果:

1

2

3

2

2

2

所有的实例都能当一个key使用了。

方法3

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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._instanceis 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)

结果:

1

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

class _singleton(object):

class ConstError(TypeError):

pass

def __setattr__(self, name, value):

if namein self.__dict__:

raise self.ConstError

self.__dict__[name]= value

def __delattr__(self, name):

if namein self.__dict__:

raise self.ConstError

raise NameError

import sys

sys.modules[__name__]= _singleton()

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

将代码存放在single.py中:

1

2

3

4

5

6

>>>import single

>>> single.a=1

>>> single.a=2

ConstError

>>>del single.a

ConstError

方法5

最简单的方法:

1

2

3

class singleton(object):

pass

singleton= singleton()

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

更多

#-*- encoding=utf-8 -*-

print '----------------------方法1--------------------------'

#方法1,实现__new__方法#并在将一个类的实例绑定到类变量_instance上,#如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回#如果cls._instance不为None,直接返回cls._instance

classSingleton(object):def __new__(cls, *args, **kw):if not hasattr(cls, '_instance'):

orig=super(Singleton, cls)

cls._instance= orig.__new__(cls, *args, **kw)returncls._instanceclassMyClass(Singleton):

a= 1one=MyClass()

two=MyClass()

two.a= 3

printone.a#3#one和two完全相同,可以用id(), ==, is检测

printid(one)#29097904

printid(two)#29097904

print one ==two#True

print one istwo#True

print '----------------------方法2--------------------------'

#方法2,共享属性;所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法)#同一个类的所有实例天然拥有相同的行为(方法),#只需要保证同一个类的所有实例具有相同的状态(属性)即可#所有实例共享属性的最简单最直接的方法就是__dict__属性指向(引用)同一个字典(dict)#可参看:http://code.activestate.com/recipes/66531/

classBorg(object):

_state={}def __new__(cls, *args, **kw):

ob= super(Borg, cls).__new__(cls, *args, **kw)

ob.__dict__ =cls._statereturnobclassMyClass2(Borg):

a= 1one=MyClass2()

two=MyClass2()#one和two是两个不同的对象,id, ==, is对比结果可看出

two.a = 3

printone.a#3

printid(one)#28873680

printid(two)#28873712

print one ==two#False

print one istwo#False#但是one和two具有相同的(同一个__dict__属性),见:

print id(one.__dict__)#30104000

print id(two.__dict__)#30104000

print '----------------------方法3--------------------------'

#方法3:本质上是方法1的升级(或者说高级)版#使用__metaclass__(元类)的高级python用法

classSingleton2(type):def __init__(cls, name, bases, dict):

super(Singleton2, cls).__init__(name, bases, dict)

cls._instance=Nonedef __call__(cls, *args, **kw):if cls._instance isNone:

cls._instance= super(Singleton2, cls).__call__(*args, **kw)returncls._instanceclassMyClass3(object):__metaclass__ =Singleton2

one=MyClass3()

two=MyClass3()

two.a= 3

printone.a#3

printid(one)#31495472

printid(two)#31495472

print one ==two#True

print one istwo#True

print '----------------------方法4--------------------------'

#方法4:也是方法1的升级(高级)版本,#使用装饰器(decorator),#这是一种更pythonic,更elegant的方法,#单例类本身根本不知道自己是单例的,因为他本身(自己的代码)并不是单例的

def singleton(cls, *args, **kw):

instances={}def_singleton():if cls not ininstances:

instances[cls]= cls(*args, **kw)returninstances[cls]return_singleton

@singletonclassMyClass4(object):

a= 1

def __init__(self, x=0):

self.x=x

one=MyClass4()

two=MyClass4()

two.a= 3

printone.a#3

printid(one)#29660784

printid(two)#29660784

print one ==two#True

print one istwo#True

one.x = 1

printone.x#1

printtwo.x#1

python单例_Python单例模式相关推荐

  1. python单例_python 单例模式

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

  2. python单例_Python - 单例模式(Singleton)

    单例模式(Singleton) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/23374575 单例模式 , 类的实例从始至终, ...

  3. python编程入门单例_Python单例模式实例详解

    本文实例讲述了Python单例模式.分享给大家供大家参考,具体如下: 单例模式:保证一个类仅有一个实例,并提供一个访问他的全局访问点. 实现某个类只有一个实例的途径: 1,让一个全局变量使得一个对象被 ...

  4. php 什么时候使用单例,php单例模式的使用场景,使用方法

    一个类只有一个对象实例 1.含义 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例.它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用. 2 ...

  5. python 模块 多线程 单例_python的单例模式

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

  6. python编程入门单例_python实现单例模式怎么写啊?

    这个网上有很多的,你可以搜一搜,单例设计模式很多面试官都会考的,最好是记住一两个,我下面写一个例子给你看一下 使用__new__方法 在__new__方法中把类实例绑定到类变量_instance上,如 ...

  7. python单例类命名_单例模式(java/python/c++)

    序 最近接触到新项目,后端基于java开发.对于有c++/python开发经验,无java经验的小梅同学,开始了漫漫学习之旅,第一篇学习记录,从最简单的单例模式开始吧. 众所周知,单例模式的最明显的几 ...

  8. python元类单例_python面向对象和元类的理解

    1 python类对象与实例对象 python中一切皆对象(广义上的对象),类也不例外,我们可以称类为类对象.python中内建函数type()可以返回对象的类型,例如type(int)会得到返回值, ...

  9. python单例设计模式(待补充)

    要点概论: 1. 理解单例设计模式 2. 单例模式中的懒汉式实例化 3. 模块级别的单例模式 4. Monostate单例模式 5. 单例和元类 6.单例模式Ⅰ 7. 单例模式Ⅱ 8. 单例模式的缺点 ...

最新文章

  1. 调用API弹出打印机属性对话框
  2. 在Objective-C中创建一个抽象类
  3. canvas——橡皮筋式线条绘图应用
  4. 【深度学习】协同优化器和结构化知识蒸馏
  5. perf stat 输出解读
  6. 《数据安全法》今日实施,中国信通院联合百度等企业发起“数据安全推进计划”
  7. Ubuntu与Mint哪个好?Linux运维发行版本推荐!
  8. CPU流水线的探秘之旅
  9. ASP.NET MVC中使用DropDownList
  10. server2019 sqlcmd命令安装_Ubuntu20.04LTS安装MS sql-server2019的方法
  11. java biz层创建代码_BIZ层调试方法
  12. 开启关闭Centos的自动更新
  13. 学python前端需要哪些基础知识_前端基础知识整理回顾~~
  14. 2022谷粒学院BUG记录
  15. 理解浏览器的历史记录
  16. linux判断分区是否为esp分区,关于ESP分区的清理
  17. 《筑墙——只需一点点安全常识就能阻止网络犯罪》
  18. ProxySQL 排错 Max connect timeout reached while reaching hostgroup 10 after 10000ms
  19. Java工程师是做什么的 岗位职责都有哪些
  20. 电点国际化翻译系统,助力你开启海外项目之旅

热门文章

  1. 计算机专业的大学生自我介绍,计算机专业大学生自我介绍
  2. 横波与纵波的本质区别是什么?——偏振
  3. 【中级软考】面向对象分析包含哪几个活动?
  4. 高斯判别分析(GDA)和朴素贝叶斯(NB)
  5. android imageview 锯齿,android 自定义圆角ImageView以及锯齿的处理
  6. 数据库php性别显示on,使用PHP连接MySQL时,提示信息为“Unknown database 'xxxx' in yyy.php on line 23”,其意思是...
  7. CentOS7下Hadoop集群搭建
  8. 如何使用idea REST Clinet 代替PostMan发送Http请求
  9. 使用Git命令时出现fatal: this operation must be run in a work tree提示,该如何解决
  10. Spring 初识Aop JDK动态代理实现 原理初显