单例模式:多次实例化指向同一个对象的模式
1,用类的属性存储实例化状态,实现单例
import settings
class MySQL:
__instance = None # 原始状态设为None
def __init__(self, ip, port):
self.ip = ip
self.port = port
@classmethod
def from_conf(cls):
if cls.__instance is None: #如果是第一次实例化,则存储实例化对象
cls.__instance = cls(settings.IP, settings.PORT)
return cls.__instance # 如果不是,则直接返回已存储的实例化对象
obj1 = MySQL.from_conf()
obj2 = MySQL.from_conf()
obj3 = MySQL.from_conf()
# obj4=MySQL('1.1.1.3',3302)
print(obj1)
print(obj2)
print(obj3)
# print(obj4)
2,用装饰器装饰类,实现单例
import settings
def singleton(cls):
_instance = cls(settings.IP, settings.PORT) # 在作用域实例化对象,准备被调用
def wrapper(*args, **kwargs):
if len(args) != 0 or len(kwargs) != 0: # 如果传入值,则重新实例化
obj = cls(*args, **kwargs)
return obj
return _instance # 如果不传值,则直接返回作用域内的实例化对象
return wrapper
@singleton # MySQL=singleton(MySQL) #MySQL=wrapper
class MySQL:
def __init__(self, ip, port):
self.ip = ip
self.port = port
# obj=MySQL('1.1.1.1',3306) #obj=wrapper('1.1.1.1',3306)
# print(obj.__dict__)
obj1 = MySQL() # wrapper()
obj2 = MySQL() # wrapper()
obj3 = MySQL() # wrapper()
obj4 = MySQL('1.1.1.3', 3302) # wrapper('1.1.1.3',3302)
print(obj1)
print(obj2)
print(obj3)
print(obj4)
3,用元类控制类的调用,实现单例
import settings
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
# self=MySQL这个类
self.__instance = self(settings.IP, settings.PORT)
def __call__(self, *args, **kwargs): # 调用类时触发
# self=MySQL这个类
if len(args) != 0 or len(kwargs) != 0: # 如果传值,则新实例化对象
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
else:
return self.__instance # 如果没有传值,则使用元类中实例化好的对象
class MySQL(metaclass=Mymeta): # MySQL=Mymeta(...)
def __init__(self, ip, port):
self.ip = ip
self.port = port
obj1 = MySQL()
obj2 = MySQL()
obj3 = MySQL()
obj4 = MySQL('1.1.1.3', 3302)
print(obj1)
print(obj2)
print(obj3)
print(obj4)
4,用模块导入的方式实现单例(模块导入只会导入一次,因此导入的对象不会再变化)\
模块中定义好的类与对象:
import settings
class MySQL:
print('run....')
def __init__(self, ip, port):
self.ip = ip
self.port = port
instance = MySQL(settings.IP, settings.PORT)
分别导入:
def f1():
from singleton import instance
print(instance)
def f2():
from singleton import instance, MySQL
print(instance)
obj = MySQL('1.1.1.3', 3302)
print(obj)
f1()
f2()
5,安全的单例模式
前四种单例模式都提供了生成新对象的接口,这种单例模式只会使用一个对象,不会再生成新对象
这种单例模式较为安全,反复生成的对象是同一个
class MySQL:
# __instance = None 也可以使用这种方法
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'instance'):
cls.instance = super().__new__(cls) # 实例化过程丢在单例处理里面,保证了单例的唯一性
cls.instance.ip = '127.0.0.1'
return cls.instance
# if cls.__instance == None:
# cls.__instance = super().__new__(cls)
# return cls.__instance
# 单例内部对象属性的实例化操作一般不再交给init方法完成
def __init__(self):
pass
m1 = MySQL()
print(m1.ip)
m2 = MySQL()
print(m2.ip)
m3 = MySQL()
m3.ip = '192.168.0.1'
print(a3.ip)
print(a2.ip)
print(a1.ip)
m4 = MySQL()
print(a4.ip)
print(a3.ip)
print(a2.ip)
print(a1.ip)