单例模式:多次实例化的结果指向同一个实例
先建一个配置文件settings
里面存放代码如下
IP='1.1.1.1'
PORT=3306
1.类里定义方法实现
import settings
class MySql:
__instance = None#定义一个隐藏属性
def __init__(self,ip,port):
self.ip=ip
self.port=port
@classmethod
def from_conf(cls):
if not cls.__instance:#如果隐藏属性为空的话,实例化一个对象,并赋值给隐藏属性
cls.__instance=cls(settings.IP,settings.PORT)
#这里如果实例化过了,就不会进入if分支,直接返回之前实例化过的 __instance
#如果没有实例化过 __instance为None ,进入if分支
return cls.__instance
obj1=MySql.from_conf()
obj2=MySql.from_conf()
print(obj1)
print(obj2)
2.利用装饰器实现
实现功能:如果实例化的时候传入参数的话,返回一个新的对象,如果没有参数,返回同一个对象
import settings
def singleton(cls):
#这行代码只会在运行到@singleton时会执行,也就是说,不管下面调用几次类,这行代码都不会再次执行
instance=cls(settings.IP,settings.PORT)#实例化一个对象,以后调用就返回这个对象...
def wrapper(*args,**kwargs):
if args or kwargs:#如果传入了参数的话
obj=cls(*args,**kwargs)#实例化一个新的对象
return obj#,并返回
return instance#如果没有参数,返回之前实例化好的instance对象
return wrapper
@singleton #等同于===>MySQL=singleton(MySQL) 返回值是wrapper =====>MySQL=wrapper
class MySql:
def __init__(self,ip,port):
self.ip=ip
self.port=port
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)#obj1,obj2,obj3都指向同一个对象(内存地址)
print(obj4)#obj4是一个新的对象
3.利用元类实现
实现功能与2相同
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 args or kwargs:#如果传入了参数
obj=self.__new__(self) #创建一个空对象
self.__init__(obj,*args, **kwargs) #为这个空对象完成初始化操作
return obj 返回初始化好的对象
else:#如果没有传入参数
return self.__instance #返回__init__里面创建好的那个对象
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)#obj1,obj2,obj3都指向同一个对象,obj4指向一个新的对象
4.利用模块导入的方式
首先自定义一个模块singleton
代码:
import settings
class MySQL:
def __init__(self, ip, port):
self.ip = ip
self.port = port
instance=MySQL(settings.IP,settings.PORT)
再在主文件里实现功能
def f1():#实现单例
from singleton import instance
#利用导入模块只会导入一次,所以instance只会创建一次,后面不管怎么调用f1,都只会返回同一个对象
print(instance)
def f2():#创建新的对象
from singleton import instance,MySQL
print(instance)
obj=MySQL('1.1.1.3',3302)
print(obj)
f1()
f2()