通过__new__()
函数
class Testclass(object):
_instance = None
def __new__(cls, *args, **kwargs):
if Testclass._instance:
return Testclass._instance
else:
Testclass._instance = super().__new__(cls)
return Testclass._instance
a = Testclass()
b = Testclass()
print(a == b)
该方法如果类中重写了__init__()
函数后会出现问题,因为__new__
是类实例化时创建实例的函数,而__init__
是类实例化中创建实例后初始化实例属性值的函数,__init__
函数调用在__new__
函数之后,所以用该方法创建单例时,虽然类实例化时__new__
每次返回的都是同一个实例对象,但是在实例化的过程中调用__new__
函数后会把__new__
函数的结果作为__init__
函数的参数再次调用__init__
函数,这就意味着虽然每次实例化得到的结果都是同一个对象,但是每次实例化都会初始化一次实例的属性值。
通过函数装饰器
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class Testclass(object):
def __init__(self):
pass
a = Testclass()
b = Testclass()
print(a == b)
使用模块
模块天然就是单例的,因为模块只会被加载一次,加载之后,其他脚本里如果使用import 二次加载这个模块时,会从sys.modules里找到已经加载好的模块,模块里的对象天然就是单例的,即使是在多线程环境下也是如此。
编写py文件my_singleton.py
class Singleton():
def __init__(self, name):
self.name = name
def do_something(self):
pass
singleton = Singleton('模块单例')
在其他文件中引入
from my_singleton import singleton
在任何引用singleton的脚本里,singleton都是同一个对象,这就确保了系统中只有一个Singleton的实例。
使用类方法
class Singleton(object):
def __init__(self, name):
self.name = name
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
single_1 = Singleton.instance('第1次创建')
single_2 = Singleton.instance('第2次创建')
print(single_1 is single_2)
instance方法会先检查是否存在类属性_instance, 如果不存在,则创建对象,并返回。这个设计虽然实现了单例模式,但在多线程环境下不安全,多个线程同时检查Singleton类是否拥有_instance属性,得到的结果是否False, 则这些线程都会执行对象的创建工作,最后创建出来的对象才是最终的对象,为了在多线程环境下保证数据安全,在需要并发枷锁的地方加上RLock锁
from threading import RLock
class Singleton(object):
single_lock = RLock()
def __init__(self, name):
self.name = name
@classmethod
def instance(cls, *args, **kwargs):
with Singleton.single_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance