今天来讲一下单例对象的使用。
单例对象模式是一种常用的软件设计模式,这种模式保证了某一个类只能有一个实例化的对象存在。当我们希望在整个程序中某个类只能有一个实例时,就可以用到这个单例模式。
使用__new__方法
使用__new__方法可以限制类只能被实例化一次,直接就用下面的方法来定义就行了
class Singleton(object): _instance = None def __new__(cls,*args,**kwargs): if not cls._instance: cls._instance = super(Singleton,cls).__new__(cls,*args,**kwargs) return cls._instance
当我们在第一次对这个类实例化一个对象的时候,类变量_instnce就会被赋值为新的对象,而再次实例化的时候cls._instance是有值的,就不会重新实例化一个新的对象。我们可以通过id来判定一下效果
a = Singleton() b = Singleton() print(id(a)) print(id(b)) ########输出######## 139968970404024 139968970404024
也就是说分别实例化的a和b其实是一个对象。
使用模块
Python的模块导入就是天然的单例模式,因为模块在第一次导入的时候就会生成一个.pyc文件,当第二次导入的 时候,就会先从pyc文件中找是否倒入过,如果以前导入过这个模块,就不再执行导入的过程。所以我们把需要的对象在模块中实例化以后导入给需要的脚本中,就是单例对象。
我们现在有个脚本文件里面定义了一个类,并且对这个类做了一个实例化
#mysingleton.py class Animal(object): def run(self): print('running...') a = Animal()
那么在另一个脚本中,我们把这个实例化后的对象导入一下
#main.py from mysingleton import a a.run()
因为这个对象a只能被导入一次,如果一个程序是由很多的脚本文件组成的,只要有一个文件导入了这个对象a,那么这个a不管在哪个脚本中被导入其实都是一个对象,即便是换了一个名称
#main.py from mysingleton import a as a1 print('a1',id(a1)) from mysingleton import a as a2 print('a2',id(a2)) ##########输出########## a1 140212539471856 a2 140212539471856
或者是有多个py脚本
#mysingleton.py class Animal(object): def run(self): print('running...') a = Animal()
有一个文件调用了这个变量a
#funcs.py from mysingleton import a def fun(): print('in fun a:',id(a))
还有一个文件导入了这个fun
#main.py from mysingleton import a import funcs funcs.fun() print('in main a',id(a))
最后运行的结论会是什么样的呢?
##########输出########## in fun a: 139630131360320 in main a 139630131360320
所以这两个脚本里导入 的一个对象就是单例对象。但是要注意的是我们导入的是一个实例化以后的对象,如果仅仅是导入类以后再在脚本中实例化那么就不是单例变量了
#main.py from mysingleton import Animal a = Animal() b = Animal() print('a',id(a)) print('b',id(b))
在上面的例子中,a和b就是一般的实例化的两个对象。
使用装饰器
这个大致看一下就行了,不作为主要的知识点
def Singleton(cls): _instance = {} def _singleton(*args,**kwargs): if cls not in _instance: _instance[cls] = cls(*args,**kwargs) return _instance[cls] return _singleton @Singleton class A(object): def fun(self): pass a = A() b = A() print('a',id(a)) print('b',id(b))
还有一种方式是使用metaclass元类,但是有些多线程的环境下会发生一些问题,我们这里就先不讲了。