3种常见方式
-
1.基于模块
python中模块是“单例”的,因为模块只在第一次被import时创建一个.pyc文件,.pyc文件创建完成后该模块的任意一次被import导入都直接加载.pyc文件从而导入模块内的同一个对象
例如,我们在模块A中定义一个类Test并实例化一个对象test
class Test:
# 此处省略类体
test = Test()
然后我们在其他所有文件中from A import test都将得到同一个test对象
**把对象写在单独的module里然后被其他文件import就是单例
-
2.基于装饰器——通过闭包保存的dict对象'_instance'来控制实例只有一个
这是很pythonic的方法。原始类并不关心自己单例与否,单例的实现只交给装饰器负责
def Singleton(cls):
_instance = dict()
def _singleton(*arg, **kw):
if cls not in _instance:
_instance[cls] = cls(*arg, **kw)
return _instance[cls]
return _singleton
@Singleton # 等价于 Test = Singleton(Test)
class Test:
# 此处省略函数体
说明:装饰器中return的是闭包_singleton,这个闭包保存了enclosing变量_instance这个字典,使得_instance这个字典一直保存在内存中,不会随着Test = Singleton(Test)完成而消失。这时,这个字典也是所谓“单例”的、唯一的,通过它来控制实例只有一个,因为在内存中只存在一个叫_instance的字典。那么,来一个类就判断一波,不在字典内就生成一个实例加入字典,然后返回这个字典中的实例,从而实现单例
局限性:被装饰的单例类不可被继承。因为一个类被装饰后,就从类变成了能够返回实例的函数,已经变成一个函数了,自然没有继承一说
-
3.重写类的new()方法
在python类实例化对象的过程中,首先类执行new()方法创建对象,然后对象执行init()方法初始化自己本身,因此可以通过重写new()实现单例模式
# 通过将类的实例对象绑定到类变量_instance上实现单例
class Singleton(object):
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
# 【下面这句是重点!!!】
cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
return cls._instance
相关说明:
super不是函数,而是一个class
所以调用super,返回的是一个super对象
>>> type(super)
<class 'type'>
>>> type(int)
<class 'type'>
可以看到,super和int一样都是type类的实例,也就是都是class。那么调用super()自然返回super对象
super(Singleton, self).new(cls, args, *kw)实现对object类的new方法调用
局限性:重写new方法可以实现单例,每次实例化对象都将得到同一个,但是每实例化对象一次,init函数就会执行一次
补充:Java中,类可以声明为static的,这时它仅包含静态成员,不能使用 new 关键字创建静态类的实例。也就是静态类不能创建实例
单例模式的话,其实和实现静态类调用静态方法在效果上是一致的。但这样一来,代码就是基于对象而不是面向对象(大家都这么说,可能还得理解一下啊。。。)
单例模式的应用:单例往往对应一个资源管理者,如保证线程池有且只有一个,保证数据库连接池有且只有一个