在某些场景下,例如创建数据库操作对象,需要只实例化一个操作对象,这时候就要用到单例模式。
注意:在项目中,不同的Python文件调用单例时,最好使用绝对路径调用,或者同时保持相对路径调用,不然可能会出现两个异常,实例化的多个单例对象不相等。
1. 直接写单例的类(不带初始化参数)
class Singleton(object):
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls.__instance
def __init__(self):
super(Singleton, self).__init__()
if __name__ == '__main__':
s1 = Singleton()
s2 = Singleton()
print(s1 == s2)
print(s1 is s2)
print(id(s1), id(s2))
输出:
True
True
1303099836400 1303099836400
2. 直接写单例的类(带初始化参数)
class Singleton(object):
__instance = None
__testNumber = 0
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super(Singleton, cls).__new__(cls)
return cls.__instance
def __init__(self, arg1):
super(Singleton, self).__init__()
self.arg1 = arg1
print(self.arg1)
if __name__ == '__main__':
s1 = Singleton("first")
s2 = Singleton("second")
print(s1 == s2)
print(s1 is s2)
print(id(s1), id(s2))
print(s1.arg1, s2.arg1)
输出:可以看到,初始化里的变量也被修改了
first
second
True
True
1345714165744 1345714165744
second second
3. 通过元类(metaclass)来实现带参数的单例模式
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class MySingleton(metaclass=SingletonMeta):
def __init__(self, param):
self.param = param
print(self.param)
if __name__ == '__main__':
s1 = MySingleton('first')
s2 = MySingleton('second')
print(s1 == s2)
print(s1 is s2)
print(id(s1), id(s2))
输出:可以看到,第二次实例化传递参数‘second’后,并没有输出,返回的是上一个实例
first
True
True
2284281329696 2284281329696
4. 装饰器实现
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class MySingleton:
def __init__(self, param):
self.param = param
print(f"Initializing param: {param}")
if __name__ == '__main__':
s1 = MySingleton('first')
s2 = MySingleton('second')
print(s1 == s2)
print(s1 is s2)
print(id(s1), id(s2))
输出:
Initializing param: first
True
True
2386541910000 2386541910000