一、什么是单例模式
整个过程中只有一个实例,所有生成的实例都指向同一块内存空间,本质是为了节省空间
class Person: def __init__(self, name, age): self.name = name self.age = age p1 = Person('yjy',18) p2 = Person('yjy',18) print(p1) #<__main__.Person object at 0x000002694B07E278> print(p2) #<__main__.Person object at 0x000002694B07E2B0>
以上p1和p2的内存空间不一样,就不是单例模式
二、实现单例模式的方法
需求:
- 当用户输入端口和地址,实例化产生新对象
- 当用户不输入端口和地址,每次拿到的对象,都是同一个
2.1 通过类的绑定方法
class Sql(): #定义一个Sql类 _instance = None #定义一个初始变量__instance=None,将第一次实例的对象传给他,有每次外面再访问就直接进行get_singleton里面的if判断 def __init__(self,port,host): self.port = port self.host = host @classmethod #运用类的绑定方法 绑定给Sql类去直接调用实例化 def get_singleton(cls): #cls为Sql # 目的是要调取Sql这个类通过从配置文件读取IP、端口参数,完成调用init方法,拿到一个实例化init方法的对象 import settings #导入模块 if not cls._instance: #如果_instance这个方法不在在类的名称空间里面 cls._instance = cls(settings.PORT,settings.HOST) #返回我们在settings里面设置好的端口号和主机号的内存地址 return cls._instance #返回这个属性的名称空间 其实就是return cls(settings.IP,settings.PORT) #每次调用get_singleton 拿到的对象都是同一个 s1 = Sql.get_singleton() #<__main__.Sql object at 0x000001BF2DCEECC0> s2 = Sql.get_singleton() #<__main__.Sql object at 0x000001BF2DCEECC0> print(s1) print(s2) s3 = Sql('33306','192.168.1.1') #重新去实例化一个东西 #Sql(ip,port) 就是调用Sql里面的init方法 print(s3) #<__main__.Sql object at 0x000001BF2DCEECF8>
#模板 class Sql(): _instance = None def __init__(self,port,host): self.port = port self.host = host @classmethod def get_singleton(cls): import settings if not cls._instance: cls._instance = cls(settings.PORT,settings.HOST) return cls._instance s1 = Sql.get_singleton() s2 = Sql.get_singleton() print(s1) print(s2) s3 = Sql('33306','192.168.1.1') print(s3)
2.2 通过装饰器
import settings def get_singleton(cls): _instance = cls(settings.PORT,settings.HOST) #给Sql的init方法传参,实例化得到一个对象,__instance def wrapper(*args,**kwargs): #判断外面调用时是否有传值进来 if len(args) ==0 and len(kwargs) == 0: # 用户没有传参, return _instance #直接返回默认settings的值 return cls(*args,**kwargs) #有用户传参,生成新对象,创建新的值,产生新的名称空间 return wrapper @get_singleton #会把下面的Sql当中参数传入,相当于:Sql=get_sigoleton(Sql) class Sql(): #Sql= singleton(Sql) Sql = wrapper def __init__(self,port,host): self.port = port self.host = host Sql = get_singleton(Sql) s1 = Sql() s2 = Sql() print(s1) #<__main__.Sql object at 0x00000188E00BE940> print(s2) #<__main__.Sql object at 0x00000188E00BE940> s3 = Sql('3306','192.168.1.2') print(s3) #<__main__.Sql object at 0x00000188E00BECC0>
#模板 import settings def get_singleton(cls): _instance = cls(settings.PORT,settings.HOST) def wrapper(*args,**kwargs): if len(args) ==0 and len(kwargs) == 0: return _instance return cls(*args,**kwargs) return wrapper @get_singleton class Sql(): def __init__(self,port,host): self.port = port self.host = host Sql = get_singleton(Sql) s1 = Sql() s2 = Sql() print(s1) print(s2) s3 = Sql('3306','192.168.1.2') print(s3)
2.3 通过元类
import settings class Mymeta(type): def __init__(self,name,bases,dic): #self是Sql类 造Sql的空对象 self._instance = self(settings.PORT,settings.HOST) #为空对象初始化独有的属性 def __call__(self, *args, **kwargs): #self是Sql类 在调用类时创建 if len(args) == 0 and len(kwargs) == 0: #如果没有传参 return self._instance #返回给空对象初始化好的属性 obj = object.__new__(self) #类的实例化产生一个新的对象用obj接收 obj.__init__(*args, **kwargs) #初始化新的obj对象 return obj #已经创建好的Sql对象 class Sql(metaclass=Mymeta): def __init__(self,port,host): self.port = port self.host = host s1 = Sql() #触发自定义类的__init__ s2 = Sql() print(s1) #<__main__.Sql object at 0x00000224460BECF8> print(s2) #<__main__.Sql object at 0x00000224460BECF8> s3 = Sql('3306','192.168.1.2') print(s3) #<__main__.Sql object at 0x000002244D0CC6A0>
#模板 import settings class Mymeta(type): def __init__(self,name,bases,dic): #self是Sql类 self._instance = self(settings.PORT,settings.HOST) def __call__(self, *args, **kwargs): #self是Sql类 if len(args) == 0 and len(kwargs) == 0: return self._instance obj = object.__new__(self) obj.__init__(*args, **kwargs) return obj class Sql(metaclass=Mymeta): def __init__(self,port,host): self.port = port self.host = host s1 = Sql() s2 = Sql() print(s1) print(s2) s3 = Sql('3306','192.168.1.2') print(s3)
2.4 导入模块实现(Python的模块是天然的单例)
'''配置文件settings''' PORT = 3306 HOST = '127.0.0.1' '''模块文件singleton''' import settings class Sql(): def __init__(self,port,host): self.port=port self.host=host s1=Sql(settings.PORT,settings.HOST) '''执行文件''' #方式一 def test(): from singleton import s1 print(s1) #这个s1和下面的s1不是一个,但是值相同 def test2(): from singleton import s1,Sql print(s1) #这个s1和上面的s1不是一个,但是值相同 obj = Sql(3306,'192.168.1.1') #传参的时候生成一个新的空对象 print(obj) #打印传进去的对象 test() #<singleton.Sql object at 0x000001D73F0AD198> test2() #<singleton.Sql object at 0x000001D73F0AD198> s3=(3308,'192.168.1.1') #<singleton.Sql object at 0x000001B0F4FEE160> #方式二 def test(): from singleton import s1 print(s1) def test2(): from singleton import s1 as s2 print(s2) test() #print(s1) <singleton.Sql object at 0x000001F578752630> test2() #print(s2) <singleton.Sql object at 0x000001F578752630> #不传参s1和s2一样 from singleton import s1 #不传参就用原来定义好的对象 from singleton import Sql s3=Sql(3306,'192.168.1.1') #传参的时候生成新的空对象 print(s3) #<singleton.Sql object at 0x000001F57172E128>