一、什么是单例模式
整个过程中只有一个实例,所有生成的实例都指向同一块内存空间,本质是为了节省空间
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>