单例

引子

基于元类实现单例模式
单例:即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省空间
场景:假若从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了)

 至少会用三种方式创建。

# 方式一:定义一个类方法实现单例模式
 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
装饰器实现单例
原文地址:https://www.cnblogs.com/limengjie0104/p/8871817.html