单例
引子
基于元类实现单例模式
单例:即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省空间
场景:假若从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了)
至少会用三种方式创建。
# 方式一:定义一个类方法实现单例模式
1 # 方式一:定义一个类方法实现单例模式 2 import setting 3 4 class Mysql: 5 instance = None 6 def __init__(self,host,port): 7 self.host = host 8 self.port = port 9 10 @classmethod 11 def from_conf(self): 12 if not Mysql.instance: 13 res = Mysql(setting.HOST, setting.PORT) 14 Mysql.instance = res 15 return Mysql.instance 16 17 # con1 = Mysql('127.0.0.1',80) # <__main__.Mysql object at 0x000000A9F7FC7978> 18 # con2 = Mysql('127.0.0.1',80) # <__main__.Mysql object at 0x000000A9F7FD8710> 19 # con3 = Mysql('127.0.0.1',80) # <__main__.Mysql object at 0x000000A9F7E09C88> 20 # print(con1,con2,con3) 21 # 22 23 # con1 = Mysql.from_conf() # <__main__.Mysql object at 0x000000BB72BA4DD8> 24 # con2 = Mysql.from_conf() # <__main__.Mysql object at 0x000000BB72BA4E48> 25 # con3 = Mysql.from_conf() # <__main__.Mysql object at 0x000000BB72BA4E80> 26 # print(con1,con2,con3) 27 28 con1 = Mysql.from_conf() # <__main__.Mysql object at 0x000000BD5BBA4DD8> 29 con2 = Mysql.from_conf() # <__main__.Mysql object at 0x000000BD5BBA4DD8> 30 con3 = Mysql.from_conf() # <__main__.Mysql object at 0x000000BD5BBA4DD8> 31 print(con1 is con2 is con3) # True
# 方式二:定义元类实现
若从配置文件取相同配置产生对象则实现单例,若传值则新建对象
1 # 方式二:定制元类实现 2 # 若从配置文件取相同配置产生对象则实现单例,若传值则新建对象 3 import setting 4 5 class Mymeta(type): 6 def __init__(self,name,bases,dic): # 定义类Mysql时就触发 7 8 # 事先从配置文件中取配置来造一个Mysql的实例出来 9 self.__instance = object.__new__(self) # 产生对象 10 self.__init__(self.__instance,setting.HOST,setting.PORT) # 初始化对象 11 #上述两步可合并下面一步 12 # self.__instance = super().__call__(*args,**kwargs) 13 14 super().__init__(name,bases,dic) 15 16 def __call__(self, *args, **kwargs): # Mysql(...)时触发 17 if args or kwargs: # Mymeta类的对象括号内传值则新建obj,否则返回self.__instance 18 obj = object.__new__(self) 19 self.__init__(obj,*args,**kwargs) 20 return obj 21 return self.__instance 22 23 24 # Mysql = Mymeta('Mysql',(obj,),class_dic) 25 class Mysql(metaclass=Mymeta): 26 def __init__(self,host,port): 27 self.host = host 28 self.port = port 29 30 con1 = Mysql() 31 con2 = Mysql() 32 con3 = Mysql() # <__main__.Mysql object at 0x0000008BA7E24DD8> 33 con4 = Mysql('127.0.0.1',80) # <__main__.Mysql object at 0x0000004B4B904EF0>,若Mymeta类的对象(Mysql)括号内传值则新建obj 34 print(con4) # True
# 方式三:装饰器实现
1 import setting 2 3 def single_obj(cls): 4 __instance = cls(setting.HOST,setting.PORT) 5 def wrapper(*args, **kwargs): 6 if args or kwargs: 7 obj = cls(*args, **kwargs) 8 return obj 9 return __instance 10 return wrapper 11 12 @single_obj 13 class Mysql: 14 def __init__(self,host,port): 15 self.host = host 16 self.port = port 17 18 con1 = Mysql() # <__main__.Mysql object at 0x0000001F978D9C88> 19 con2 = Mysql() # <__main__.Mysql object at 0x0000001F978D9C88> 20 con3 = Mysql('127.0.0.1',80) # <__main__.Mysql object at 0x0000001F98AE4DD8> 21 22 print(con1 is con2) # True