单例模式
单例模式
1、什么是单例模式
单例模式是一种设计模式
让所有类在实例化时,指向同一个内存地址,称之为单例模式 PS:无论产生多少个对象,都会指向 单个 实例
当在确定 "类中的属性与方法不变" 需要反复调用类时,会产生不同的对象,也会产生不同的内存地址,最终造成资源的浪费,如下例:
class Foo:
def __init__(self, x, y):
self.x = x
self.y = y
foo_obj1 = Foo(10, 20)
print(foo_obj1.__dict__)
print(foo_obj1)
foo_obj2 = Foo(10, 20)
print(foo_obj2.__dict__)
print(foo_obj2)
执行结果:
# foo_obj1和foo_obj2调用的属性相同,但内存地址不同
{'x': 10, 'y': 20}
<__main__.Foo object at 0x0000000001E662C8> # foo_obj1的内存地址
{'x': 10, 'y': 20}
<__main__.Foo object at 0x0000000001E66408> # foo_obj2的内存地址
使用多个内存地址即浪费内存空间。
2、单例模式的优点
可以节省内存空间
3、单例模式实现方法
实现方法(*****):
1) 通过classmethod实现
2) 通过__new__实现
3) 通过装饰器实现
4) 通过导入模块时实现
5) 通过元类实现
1) 通过classmethod实现
模板:
class Singleton: __instance = None @classmethod def singleton(cls): if not cls.__instance: cls.__instance = cls() return cls.__instance # 调用阶段 obj1 = Singleton() print(obj1) obj2 = Singleton() print(obj2) obj3 = Singleton() print(obj3)
执行结果:
<__main__.Singleton object at 0x000001B878D24BE0> <__main__.Singleton object at 0x000001B878D24710> <__main__.Singleton object at 0x000001B878D53F60>
例:假如数据库被多台服务器调用启动和关闭(使用classmethod实现)
class MySql:
# 定义一个属性默认值,用于判断对象是否存在, 若对象不存在,属性值默认是None
# __instance是类的属性
__instance = None
def __init__(self, host, port):
self.host = host
self.port = port
@classmethod
def singleton(cls, host, port): # 单例方法 --> 类方法
# 判断__instance中若没有值,证明没有对象
if not cls.__instance:
# 产生一个对象并返回
obj = cls(host, port)
# 从 None --> obj
cls.__instance = obj
# 若__instance有值,证明对象已经存在,则直接返回该对象
return cls.__instance
def start_mysql(self):
print("启动数据库。")
def stop_mysql(self):
print("关闭数据库。")
HOST1 = "192.168.9.1"
PORT1 = "1532"
HOST2 = "192.168.9.2"
PORT2 = "1533"
HOST3 = "192.168.9.3"
PORT3 = "1534"
obj1 = MySql.singleton(HOST1, PORT1)
obj2 = MySql.singleton(HOST2, PORT2)
obj3 = MySql.singleton(HOST3, PORT3)
print(obj1)
print(obj2)
print(obj3)
执行结果:
# obj1、obj2、obj3调用的属性相同,内存地址也相同 <__main__.MySql object at 0x00000000021D6D48> # obj1的内存地址 <__main__.MySql object at 0x00000000021D6D48> # obj2的内存地址 <__main__.MySql object at 0x00000000021D6D48> # obj3的内存地址
使用同一个内存地址即节省内存空间。
2) 通过__new__实现:通过onject的__new__方法创建空对象
模板:
class Singleton: __instance = None def __new__(cls, *args, **kwargs): if not cls.__instance: # 创造一个空对象 cls.__instance = object.__new__(cls) return cls.__instance # 调用阶段 obj1 = Singleton() print(obj1) obj2 = Singleton() print(obj2) obj3 = Singleton() print(obj3)
执行结果:
<__main__.Singleton object at 0x000002046AA64C88> <__main__.Singleton object at 0x000002046AA64C88> <__main__.Singleton object at 0x000002046AA64C88>
3) 通过装饰器实现
模板:
def singleton(cls): # cls --> Father _instance = {} def inner(*args, **kwargs): if cls not in _instance: obj = cls(*args, **kwargs) _instance[cls] = obj return _instance[cls] return inner @singleton class Father: pass
4) 通过导入模块时实现
模板:
from Singleton import SingletonCls, obj obj1 = SingletonCls() obj2 = SingletonCls() # 变 print(obj1) print(obj2) # 不变,调用的是同一个对象,所以内存地址相同 print(obj) print(obj)
执行结果:
<Singleton.SingletonCls object at 0x00000244AC274C50> # obj1 <Singleton.SingletonCls object at 0x00000244AC274780> # obj2 <Singleton.SingletonCls object at 0x00000244AC343CF8> # obj <Singleton.SingletonCls object at 0x00000244AC343CF8> # obj