转自 https://blog.csdn.net/u012324798/article/details/104056562
本文在比较了Python实现单例模式8种方法的优缺点之后,认为在Python中使用元类实现单例模式效果最好,推荐使用元类实现单例。
通常情况下,一个类可以多次实例化,每个实例对象是相互独立的,即类在同一时刻可以有多种实例状态。
如果我们希望:
某个类在在同一时刻不能有多种实例状态,即【单态】(例如:操作系统的任务管理器、回收站、文件系统;应用程序的日志应用、网站的计时工具或ID(序号)生成器);或者某个类只需要一个实例就够用了,即【单例】,多的实例不会有什么坏的影响,但也没什么作用,只是徒增资源消耗而已(例如:数据库连接池、线程池、web开发中读取配置文件)。这时如果某个类在程序运行期间只有一个实例,就能实现上述需求(单例 / 单态)。
最简单的办法就是只实例化一次得到一个实例,自己记住,之后写代码的时候一直用它,不再实例化。问题是自己有可能忘了某个类已经实例化过了,而且别人想复用你的代码时也不知道你已经实例化过了,就很容易发生重复实例化,自然无法确保单例效果。为了解决这个问题,我们希望在这个类本身能够实现无论实例化多少次,每次返回的都是同一个实例的效果,这就是单例模式。这样后续使用这个类的人就无需关注是否已经实例化过,反正重复实例化得到的还是单例。
类():即obj = MyClass() ,执行MyClass的元类的__call__方法,如果没有使用metaclass指定元类,则默认元类为type 实例():即obj(),执行MyClass类的__call__方法
obj = MyClass() 这一实例化过程其实是调用其元类的__call__方法,如果未指定元类,则调用默认元类type的__call__方法,而这一方法是由type_call函数(CPython 中的 C代码)来实现的,其实现的基本逻辑简化后相当于Python的以下代码:即先调用MyClass的__new__方法创建实例,如果实例符合2个条件,则调用MyClass的__init__方法对实例进行初始化。
def __call__(obj_type, *args, **kwargs): obj = obj_type.__new__(*args, **kwargs) if obj is not None and isinstance(obj, obj_type): obj.__init__(*args, **kwargs) return obj由此可见,控制实例化过程的是3个特殊方法:
元类的__call__方法是实例化过程中最早调用的方法,它控制了类的__new__和__init__方法的调用类的__new__方法是第二个调用的方法,影响创建实例的具体过程类的__init__方法是最后调用的方法,影响实例的初始化想要让MyClass成为单例模式,在实例化过程前加上条件判断就可以。问题是在哪里增加条件判断的代码?由于条件判断的代码所在位置不同,单例模式有多种实现方式。本文的重点就是比较分析这些实现方式的优缺点。
为了比较网上比较流行的Python实现单例模式的8种方法,提出以下评价标准:
将单例模式的代码独立封装为Singleton方便复用,MyClass及其子类SubClass无需关心单例模式的实现MyClass类有继承的基类OtherClass时不影响单例效果单例模式不影响MyClass作为基类被SubClass继承,且子类SubClass也是单例模式,即SubClass每次实例化得到都是同一个SubClass实例变量MyClass代表的是真正的MyClass类,能使用类属性、类方法type(obj) 返回的是真正的MyClass类type(obj) () 返回的也是单例,单例效果稳定有 lazy loading的效果,即导入模块时没有发生实例化,不消耗资源,等到需要使用时再实例化多线程并发环境下得到的也是单例除了实现方式(一)、(二)以外,都使用以下测试代码: test.py
import threading import time from singleton_class import MyClass def print_task(obj=None, arg=1): if obj is None: obj = MyClass() before = obj.__dict__ print('arg: %d, id(obj): %d' % (arg, id(obj))) print('arg: %d, before: %s' % (arg, before)) obj.x = 'x_%d' % arg obj.a = 'a_%d' % arg if hasattr(obj, 'y'): obj.y = 'y_%d' % arg after = obj.__dict__ print('arg: %d, after: %s' % (arg, after)) if __name__ == '__main__': print('_____________________________MyClass MultiThreading Test______________________________________') for i in range(1, 11): t = threading.Thread(target=print_task, args=(None, i)) t.start() time.sleep(4) print('_____________________________MyClass______________________________________') print('MyClass: %s, type(MyClass): %s' % (MyClass, type(MyClass))) try: print('MyClass.class_attribute(): %s' % MyClass.class_attribute) MyClass.class_func() except AttributeError: print('由于type(MyClass): %s,变量MyClass不能使用类属性、类方法' % type(MyClass)) obj1 = MyClass() print_task(obj1, 1) obj2 = MyClass() print_task(obj2, 2) print('type(obj): %s' % type(obj1)) obj3 = type(obj1)() print_task(obj3, 3) print('_____________________________SubClass______________________________________') try: class SubClass(MyClass): def __init__(self): super(SubClass, self).__init__() self.y = 'y_default' # # 实现方式(五)、(六)SubClass需改用以下代码 # class SubClass(MyClass): # def __init__(self): # # __init__方法需避免重复初始化成员变量 # if not self._initialed: # super(SubClass, self).__init__() # self.y = 'y_default' # self._initialed = True print('SubClass: %s, type(SubClass): %s' % (SubClass, type(SubClass))) print('SubClass.class_attribute(): %s' % SubClass.class_attribute) SubClass.class_func() sub_obj1 = SubClass() print_task(sub_obj1, 11) sub_obj2 = SubClass() print_task(sub_obj2, 12) print('type(sub_obj): %s' % type(sub_obj1)) sub_obj3 = type(sub_obj1)() print_task(sub_obj3, 13) except TypeError: print('由于type(MyClass): %s,变量MyClass不能作为基类被继承' % type(MyClass))此实现方式将条件判断的代码放在了类方法 getInstance 中,必须调用类方法 getInstance 作为获取实例的接口才能获得单例,如果使用 obj = MyClass() 这种常规方式,则获取到的不是单例,非常不实用,就不测试分析了,直接跳过。
class MyClass(object): _instance = None def __init__(self): self.x = 0 @classmethod def get_instance(cls): if cls._instance is None: cls._instance = cls() return cls._instance此实现方式没有增加条件判断的代码,而是借助了模块的单例特性,确保只有一个实例存在。为什么Python模块就是天然的单例模式?
由于在程序运行期间模块只装载一次,并且模块A中的全局变量a绑定成了模块的属性,即A.a只有一个。如果A.a代表的是实例,并且切断了其他实例化的途径,则该类的实例就只有一个。
在声明 MyClass 类之后直接实例化一个单例保存在同名的全局变量 MyClass 中,即MyClass = MyClass(),这样变量 MyClass 代表的就是一个实例,不是类,也就不能通过 obj = MyClass() 这行代码进行实例化,会报错。为了不让这个这行代码报错,给MyClass类增加一个__call__方法(使得实例可以向函数一样通过 () 被调用),返回实例本身。这样每次通过 obj = MyClass() 这行代码进行“实例化”时,并没有真正进行实例化,而是调用了实例的__call__方法,返回实例本身,从而实现了单例模式。
singleton_class.py
import time class Singleton(object): # 给单例类增加一个__call__方法,返回实例本身 def __call__(self, *args, **kwargs): return self class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() class MyClass(Singleton, OtherClass): class_attribute = 'class_default' def __init__(self): time.sleep(1) # 注意:由于模块装载后,变量 MyClass 代表的是实例,不是类,不能使用super(MyClass, self).__init__() # 要获得真实的MyClass类,需使用__class__ super(__class__, self).__init__() self.x = 'x_default' @classmethod def class_func(cls): print('class function') # 同名实例替换类变量 MyClass = MyClass()test.py
import threading import time def print_task(obj, arg): before = obj.__dict__ print('arg: %d, id(obj): %d' % (arg, id(obj))) print('arg: %d, before: %s' % (arg, before)) obj.x = 'x_%d' % arg obj.a = 'a_%d' % arg if hasattr(obj, 'y'): obj.y = 'y_%d' % arg after = obj.__dict__ print('arg: %d, after: %s' % (arg, after)) def task(arg): print('arg: %d before import' % arg) # import语句是线程安全的,即使多线程并发导入同一个模块,也不会重复装载模块 from singleton_class import MyClass print_task(MyClass(), arg) if __name__ == '__main__': print('_____________________________MyClass MultiThreading Test______________________________________') for i in range(1, 11): t = threading.Thread(target=task, args=(i, )) t.start() time.sleep(2) from ingleton_class import MyClass print('_____________________________MyClass______________________________________') print('type(MyClass): %s' % type(MyClass)) print('MyClass.class_attribute(): %s' % MyClass.class_attribute) MyClass.class_func() obj1 = MyClass() print_task(obj1, 1) obj2 = MyClass() print_task(obj2, 2) obj3 = type(obj1)() print_task(obj3, 3) print('_____________________________SubClass______________________________________') # 注意:变量MyClass代表的是实例,不是类,不能直接用变量MyClass作为基类,而需使用MyClass.__class__作为基类 class SubClass(MyClass.__class__): def __init__(self): # 由于模块装载后,变量 SubClass 代表的是实例,不是类,不能使用super(SubClass, self).__init__() # 要获得真实的SubClass类,需使用__class__ super(__class__, self).__init__() self.y = 'y_default' # 同名实例替换类变量 SubClass = SubClass() print('SubClass: %s, type(SubClass): %s' % (SubClass, type(SubClass))) print('SubClass.class_attribute(): %s' % SubClass.class_attribute) SubClass.class_func() sub_obj1 = SubClass() print_task(sub_obj1, 11) sub_obj2 = SubClass() print_task(sub_obj2, 12) print('type(sub_obj): %s' % type(sub_obj1)) sub_obj3 = type(sub_obj1)() print_task(sub_obj3, 13)输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1 before import arg: 2 before import arg: 3 before import arg: 4 before import arg: 5 before import arg: 6 before import arg: 7 before import arg: 8 before import arg: 9 before import arg: 10 before import arg: 1, id(obj): 40451880 arg: 1, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 40451880 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, id(obj): 40451880 arg: 3, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, id(obj): 40451880 arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 5, id(obj): 40451880 arg: 5, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 5, after: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, id(obj): 40451880 arg: 6, before: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, after: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 4, before: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 4, after: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 7, id(obj): 40451880 arg: 8, id(obj): 40451880 arg: 8, before: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 7, before: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 7, after: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, after: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, id(obj): 40451880 arg: 9, before: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 10, id(obj): 40451880 arg: 10, before: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 10, after: {‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 9, after: {‘a’: ‘a_9’, ‘x’: ‘x_9’} _____________________________ MyClass______________________________________ MyClass: <singleton_class.MyClass object at 0x0000000002693F28>, type(MyClass): <class ‘singleton_class.MyClass’> MyClass.class_attribute(): class_default class function arg: 1, id(obj): 40451880 arg: 1, before: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 40451880 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.MyClass’> arg: 3, id(obj): 40101928 arg: 3, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} _____________________________ SubClass______________________________________ SubClass: <__ main__.SubClass object at 0x00000000026752E8>, type(SubClass): <class ‘__ main__.SubClass’> SubClass.class_attribute(): class_default class function arg: 11, id(obj): 40325864 arg: 11, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’, ‘y’: ‘y_default’} arg: 11, after: {‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, id(obj): 40325864 arg: 12, before: {‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, after: {‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} type(sub_obj): <class ‘__ main__.SubClass’> arg: 13, id(obj): 40326032 arg: 13, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’, ‘y’: ‘y_default’} arg: 13, after: {‘a’: ‘a_13’, ‘x’: ‘x_13’, ‘y’: ‘y_13’}
优点:
(核心优点)无需设置双重校验锁,自动实现在多线程并发环境下仍然是单例,原因是实例化发生在模块装载时,而import语句是线程安全的,即使多线程并发导入同一个模块,也不会重复装载模块,从而确保了只有一个实例存在MyClass类有继承的基类OtherClass时不影响单例效果变量MyClass代表的是MyClass类的实例,能使用类属性、类方法type(obj) 返回的是真正的MyClass类缺点:
单例模式的代码不能完全独立封装,MyClass类及其子类SubClass为了实现单例模式,必须注意使用同名实例替换类变量单例模式影响MyClass作为基类被SubClass继承,因为变量MyClass代表的是实例,不是类,不能直接用变量MyClass作为基类,而需使用MyClass.__class__作为基类通过obj3 = type(obj1)() 得到的实例 obj3 不是单例,单例效果不稳定没有达到lazy loading的效果,在装载模块时就完成实例化了此实现方式将MyClass这个变量替换为函数装饰器,从而可以在装饰器中进行条件判断。由于装饰器只是替换了MyClass这个变量,真正的实例化过程并未开始,当符合条件判断时,只需通过 obj = MyClass() 这种常规方式完成实例化即可。
singleton_class.py
import threading import time # 写法1 def Singleton(cls): _instance = dict() _instance_lock = threading.Lock() def _wrapper(*args, **kargs): # 外层校验是为了避免单例已产生后,线程还要拿锁,浪费锁资源 if cls not in _instance: with _instance_lock: # 内层校验是单例逻辑的条件判断,必须放在锁内,是为了避免线程在等锁的过程中单例已产生 if cls not in _instance: _instance[cls] = cls(*args, **kargs) return _instance[cls] return _wrapper # # 写法2 # def Singleton(cls): # _instance = None # _instance_lock = threading.Lock() # # def _wrapper(*args, **kargs): # nonlocal _instance # # 外层校验是为了避免单例已产生后,线程还要拿锁,浪费锁资源 # if _instance is None: # with _instance_lock: # # 内层校验是单例逻辑的条件判断,必须放在锁内,是为了避免线程在等锁的过程中单例已产生 # if _instance is None: # _instance = cls(*args, **kargs) # return _instance # # return _wrapper class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() @Singleton class MyClass(OtherClass): class_attribute = 'class_default' def __init__(self): time.sleep(1) # 注意:经过装饰后的变量 MyClass 代表的是函数,不是类,不能使用super(MyClass, self).__init__() # 要获得真实的MyClass类,需使用__class__ super(__class__, self).__init__() self.x = 'x_default' @classmethod def class_func(cls): print('class function')输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1, id(obj): 39810552 arg: 2, id(obj): 39810552 arg: 2, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 1, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, id(obj): 39810552 arg: 4, id(obj): 39810552 arg: 3, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 5, id(obj): 39810552 arg: 5, before: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 5, after: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 4, before: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, id(obj): 39810552 arg: 7, id(obj): 39810552 arg: 7, before: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, before: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, after: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, after: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 4, after: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 8, id(obj): 39810552 arg: 8, before: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 8, after: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, id(obj): 39810552 arg: 9, before: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, after: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, id(obj): 39810552 arg: 10, before: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, after: {‘a’: ‘a_10’, ‘x’: ‘x_10’} _____________________________ MyClass______________________________________ MyClass: <function Singleton.< locals >._ wrapper at 0x00000000025EEEA0>, type(MyClass): <class ‘function’> 由于type(MyClass): <class ‘function’>,变量MyClass不能使用类属性、类方法 arg: 1, id(obj): 39810552 arg: 1, before: {‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39810552 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.MyClass’> arg: 3, id(obj): 39727056 arg: 3, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} _____________________________ SubClass______________________________________ 由于type(MyClass): <class ‘function’>,变量MyClass不能作为基类被继承
优点:
将单例模式的代码独立封装,MyClass类无需关心单例模式的实现MyClass有继承的基类OtherClass时不影响单例效果type(obj) 返回的是真正的MyClass类有 lazy loading 效果缺点:
单例模式导致MyClass不能作为基类被SubClass继承经过装饰后的变量MyClass代表的是一个_wrapper函数,而不是真正的MyClass类,不能使用MyClass的类属性、类方法obj3 = type(obj1)() 得到的实例 obj3 不是单例,单例效果不稳定需手动设置双重校验锁,才能在保证多线程并发环境下得到的也是单例此实现方式与(三)使用函数装饰器非常相似,没有本质区别,只不过装饰器的写法不同。 singleton_class.py
import threading import time class Singleton(object): _instance_lock = threading.Lock() def __init__(self, cls): self._cls = cls self._instance = None def __call__(self, *args, **kwargs): if self._instance is None: with Singleton._instance_lock: if self._instance is None: self._instance = self._cls(*args, **kwargs) return self._instance class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() @Singleton class MyClass(OtherClass): class_attribute = 'class_default' def __init__(self): time.sleep(1) # 注意:经过装饰后的变量 MyClass 代表的是实例,不是类,不能使用super(MyClass, self).__init__() # 要获得真实的MyClass类,需使用__class__ super(__class__, self).__init__() self.x = 'x_default' @classmethod def class_func(cls): print('class function')输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1, id(obj): 39923272 arg: 2, id(obj): 39923272 arg: 2, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 1, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, id(obj): 39923272 arg: 3, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, id(obj): 39923272 arg: 4, before: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, after: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, id(obj): 39923272 arg: 5, before: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, after: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, id(obj): 39923272 arg: 6, before: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, after: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, id(obj): 39923272 arg: 7, before: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 8, id(obj): 39923272 arg: 7, after: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 9, id(obj): 39923272 arg: 8, before: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, after: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 10, id(obj): 39923272 arg: 9, before: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, after: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, before: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, after: {‘a’: ‘a_10’, ‘x’: ‘x_10’} _____________________________ MyClass______________________________________ MyClass: <singleton_class.Singleton object at 0x00000000026260B8>, type(MyClass): <class ‘singleton_class.Singleton’> 由于type(MyClass): <class ‘singleton_class.Singleton’>,变量MyClass不能使用类属性、类方法 arg: 1, id(obj): 39923272 arg: 1, before: {‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39923272 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.MyClass’> arg: 3, id(obj): 39744456 arg: 3, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} _____________________________ SubClass______________________________________ 由于type(MyClass): <class ‘singleton_class.Singleton’>,变量MyClass不能作为基类被继承
优缺点与函数装饰器相同,区别在于经过装饰后的变量MyClass代表的是Singleton类(装饰器)的实例,它也不代表真正的MyClass类。
在实现方式(三)、(四)中,经过装饰后的变量MyClass代表的都不是类,不能作为基类被SubClass继承,为了解决这个问题,考虑使用装饰器返回类的实现方式。
由实例化过程原理分析,我们知道了:类的__new__方法是第二个调用的方法,影响创建实例的具体过程;类的__init__方法是最后调用的方法,影响实例的初始化。
那么,通过在类的__new__方法增加条件判断的代码,就能实现单例模式。但是没这么简单,必须要注意三个问题:
每次调用__new__方法之后,会紧接着调用__init__方法。所以,必须给出一个标志,避免__init__方法重复调用导致成员变量被默认值覆盖。多线程并发环境下,如果MyClass类的__init__方法中有耗时操作,则装饰器内的__init__方法也要加双重校验锁。经过装饰后的变量MyClass代表的是class_wrapper类,从而SubClass继承的就是class_wrapper类,但SubClass真正想要继承的是MyClass类。于是,为了能够让SubClass继承到MyClass类,class_wrapper类必须继承于MyClass类。singleton_class.py
import threading import time def Singleton(_cls): # 为了能够让SubClass继承到MyClass类,class_wrapper类必须继承于MyClass类 class class_wrapper(_cls): # 由于class_wrapper的类属性_instance被所有单例类共享,为保证各单例类之间相互独立,_instance需使用可变数据类型(例如:字典) _instance = dict() _instance_lock = threading.Lock() def __new__(cls): if cls not in class_wrapper._instance.keys(): with class_wrapper._instance_lock: if cls not in class_wrapper._instance.keys(): class_wrapper._instance[cls] = super(class_wrapper, cls).__new__(cls) # 需给出一个标志,从而__init__方法可以根据此标志避免重复初始化成员变量 class_wrapper._instance[cls]._intialed = False return class_wrapper._instance[cls] def __init__(self): # __init__方法需避免重复初始化成员变量,并且加双重校验锁 if not self._intialed: with class_wrapper._instance_lock: if not self._intialed: super(class_wrapper, self).__init__() self._intialed = True class_wrapper.__name__ = _cls.__name__ return class_wrapper class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() @Singleton class MyClass(OtherClass): class_attribute = 'class_default' def __init__(self): time.sleep(1) # 注意:经过装饰后的变量 MyClass 代表的是class_wrapper类,而不是真实的MyClass类,不能使用super(MyClass, self).__init__() # 要获得真实的MyClass类,需使用__class__ super(__class__, self).__init__() self.x = 'x_default' @classmethod def class_func(cls): print('class function')注意: test.py中的SubClass需改为以下代码
# 实现方式(五)、(六)SubClass需改用以下代码 class SubClass(MyClass): def __init__(self): # __init__方法需避免重复初始化成员变量 if not self._initialed: super(SubClass, self).__init__() self.y = 'y_default' self._initialed = True 123456789输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1, id(obj): 39289072 arg: 1, before: {’_ intialed’: True, ‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 1, after: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39289072 arg: 2, before: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, id(obj): 39289072 arg: 3, before: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {’_ intialed’: True, ‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, id(obj): 39289072 arg: 4, before: {’_ intialed’: True, ‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, after: {’_ intialed’: True, ‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, id(obj): 39289072 arg: 5, before: {’_ intialed’: True, ‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, after: {’_ intialed’: True, ‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, id(obj): 39289072 arg: 6, before: {’_ intialed’: True, ‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, after: {’_ intialed’: True, ‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, id(obj): 39289072 arg: 7, before: {’_ intialed’: True, ‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, after: {’_ intialed’: True, ‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, id(obj): 39289072 arg: 8, before: {’_ intialed’: True, ‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, after: {’_ intialed’: True, ‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, id(obj): 39289072 arg: 9, before: {’_ intialed’: True, ‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, after: {’_ intialed’: True, ‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, id(obj): 39289072 arg: 10, before: {’_ intialed’: True, ‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, after: {’_ intialed’: True, ‘a’: ‘a_10’, ‘x’: ‘x_10’} _____________________________ MyClass______________________________________ MyClass: <class ‘singleton_class.Singleton.< locals >.class_wrapper’>, type(MyClass): <class ‘type’> MyClass.class_attribute(): class_default class function arg: 1, id(obj): 39289072 arg: 1, before: {’_ intialed’: True, ‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 1, after: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39289072 arg: 2, before: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.Singleton.< locals >.class_wrapper’> arg: 3, id(obj): 39289072 arg: 3, before: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {’_ intialed’: True, ‘a’: ‘a_3’, ‘x’: ‘x_3’} _____________________________ SubClass______________________________________ SubClass: <class ‘__ main__.SubClass’>, type(SubClass): <class ‘type’> SubClass.class_attribute(): class_default class function arg: 11, id(obj): 39187120 arg: 11, before: {’_ initialed’: True, ‘a’: ‘a_default’, ‘x’: ‘x_default’, ‘y’: ‘y_default’} arg: 11, after: {’_ initialed’: True, ‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, id(obj): 39187120 arg: 12, before: {’_ initialed’: True, ‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, after: {’_ initialed’: True, ‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} type(sub_obj): <class ‘__ main__.SubClass’> arg: 13, id(obj): 39187120 arg: 13, before: {’_ initialed’: True, ‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} arg: 13, after: {’_ initialed’: True, ‘a’: ‘a_13’, ‘x’: ‘x_13’, ‘y’: ‘y_13’}
优点:
MyClass类无需关心单例模式的实现MyClass有继承的基类OtherClass时不影响单例效果单例模式不影响MyClass作为基类被继承,且子类SubClass也是单例模式,即SubClass每次实例化得到都是同一个SubClass实例经过装饰后的变量MyClass代表了class_wrapper类,它是MyClass类的子类,从而能使用MyClass类的类属性、类方法通过obj3 = type(obj1)() 得到的实例也是单例,单例效果稳定有 lazy loading 效果缺点:
单例模式的代码不能完全独立封装,子类SubClass需关心单例模式的实现(必须注意不能重载__new__方法,否则SubClass不是单例模式;__init__方法需注意避免重复初始化成员变量)type(obj) 返回的是class_wrapper类,不是真正的MyClass类,即obj实际上是class_wrapper类的单例需手动设置双重校验锁,才能在保证多线程并发环境下得到的也是单例在实现方式(五)中,经过装饰后的变量MyClass代表了class_wrapper类,不是真正的MyClass类。为了解决这个问题,考虑使用基类的实现方式。
这种实现方式也是通过在类的__new__方法增加条件判断的代码。但是Singleton是基类,MyClass是子类,基类无法控制子孙类方法的调用,因此必须要注意三个问题:
每次调用__new__方法之后,会紧接着调用__init__方法。所以,必须给出一个标志,避免__init__方法重复调用导致成员变量被默认值覆盖。基类Singleton无法控制子孙类方法的调用,如果子孙类有自己特殊的成员变量需要初始化,则__init__方法不能封装到基类Singleton中。多线程并发环境下,如果__init__方法中有耗时操作,则__init__方法也要加双重校验锁。singleton_class.py
import threading import time class Singleton(object): # 由于Singleton的类属性_instance被所有单例类共享,为保证各单例类之间相互独立,_instance需使用可变数据类型(例如:字典) _instance = dict() _instance_lock = threading.Lock() def __new__(cls, *args, **kwargs): if cls not in Singleton._instance.keys(): with Singleton._instance_lock: if cls not in Singleton._instance.keys(): Singleton._instance[cls] = super(Singleton, cls).__new__(cls) # 需给出一个标志,从而__init__方法可以根据此标志避免重复初始化成员变量 Singleton._instance[cls]._intialed = False return Singleton._instance[cls] class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() class MyClass(Singleton, OtherClass): class_attribute = 'class_default' def __init__(self): # __init__方法需避免重复初始化成员变量,并且加双重校验锁 if not self._initialed: with self._instance_lock: if not self._initialed: super(MyClass, self).__init__() time.sleep(1) self.x = 'x_default' self._initialed = True @classmethod def class_func(cls): print('class function')注意: test.py中的SubClass需改为以下代码
# 实现方式(五)、(六)SubClass需改用以下代码 class SubClass(MyClass): def __init__(self): # __init__方法需避免重复初始化成员变量 if not self._initialed: super(SubClass, self).__init__() self.y = 'y_default' self._initialed = True输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1, id(obj): 39579888 arg: 1, before: {’_ intialed’: True, ‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 1, after: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39579888 arg: 2, before: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, id(obj): 39579888 arg: 3, before: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {’_ intialed’: True, ‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, id(obj): 39579888 arg: 4, before: {’_ intialed’: True, ‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, after: {’_ intialed’: True, ‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, id(obj): 39579888 arg: 5, before: {’_ intialed’: True, ‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, after: {’_ intialed’: True, ‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, id(obj): 39579888 arg: 6, before: {’_ intialed’: True, ‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, after: {’_ intialed’: True, ‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, id(obj): 39579888 arg: 7, before: {’_ intialed’: True, ‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, after: {’_ intialed’: True, ‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, id(obj): 39579888 arg: 8, before: {’_ intialed’: True, ‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 9, id(obj): 39579888 arg: 9, before: {’_ intialed’: True, ‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, after: {’_ intialed’: True, ‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, after: {’_ intialed’: True, ‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, id(obj): 39579888 arg: 10, before: {’_ intialed’: True, ‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, after: {’_ intialed’: True, ‘a’: ‘a_10’, ‘x’: ‘x_10’}MyClass_________ MyClass: <class ‘singleton_class.MyClass’>, type(MyClass): <class ‘type’> MyClass.class_attribute(): class_default class function arg: 1, id(obj): 39579888 arg: 1, before: {’_ intialed’: True, ‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 1, after: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39579888 arg: 2, before: {’_ intialed’: True, ‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.MyClass’> arg: 3, id(obj): 39579888 arg: 3, before: {’_ intialed’: True, ‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {’_ intialed’: True, ‘a’: ‘a_3’, ‘x’: ‘x_3’} _____________________________ SubClass______________________________________ SubClass: <class ‘__ main__.SubClass’>, type(SubClass): <class ‘type’> SubClass.class_attribute(): class_default class function arg: 11, id(obj): 39974392 arg: 11, before: {’_ intialed’: True, ‘a’: ‘a_default’, ‘x’: ‘x_default’, ‘y’: ‘y_default’} arg: 11, after: {’_ intialed’: True, ‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, id(obj): 39974392 arg: 12, before: {’_ intialed’: True, ‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, after: {‘intialed’: True, ‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} type(sub_obj): <class '_ main__.SubClass’> arg: 13, id(obj): 39974392 arg: 13, before: {’_ intialed’: True, ‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} arg: 13, after: {’_ intialed’: True, ‘a’: ‘a_13’, ‘x’: ‘x_13’, ‘y’: ‘y_13’}
优点:
MyClass类有继承的基类OtherClass时不影响单例效果(前提条件:Singleton需作为第一基类)单例模式不影响MyClass类作为基类被继承,且子类SubClass也是单例模式,即SubClass每次实例化得到都是同一个SubClass实例变量MyClass代表的是真正的MyClass类,能使用类属性、类方法type(obj) 返回的是真正的MyClass类通过obj3 = type(obj1)() 得到的实例也是单例,单例效果稳定有 lazy loading 效果缺点:
单例模式的代码不能完全独立封装,MyClass类、SubClass类需关心单例模式的实现(必须注意不重载__new__方法,否则不是单例;__init__方法需避免重复初始化成员变量;Singleton需作为第一基类)需手动设置双重校验锁,才能在保证多线程并发环境下得到的也是单例实现方式(五)、(六)都是通过在类的__new__方法中增加条件判断的代码来实现单例模式的,导致单例模式的代码不能完全独立封装。
回顾实例化过程的原理,元类的__call__方法是实例化过程中最早调用的方法,从而可以在元类的__call__方法中增加条件判断。
需要注意的是,由于此时实例化过程已开始,当符合条件判断时,需通过super函数调用父元类type的__call__方法完成实例化。
singleton_class.py
import threading import time # 写法1 # 元类Singleton不保存所有单例类的实例,各单例类通过自己的类属性cls._instance保存单例 class Singleton(type): _instance_lock = threading.Lock() # 元类的__init__方法负责在类创建后初始化类属性 def __init__(cls, *args, **kwargs): # 虽然子类SubClass创建时继承了基类MyClass的类属性_instance,但是会在此处被重置为None,从而SubClass也是单例模式 cls._instance = None super(Singleton, cls).__init__(*args, **kwargs) def __call__(cls, *args, **kwargs): # 外层校验是为了避免单例已产生后,线程还要拿锁,浪费锁资源 if cls._instance is None: with Singleton._instance_lock: # 内层校验是单例逻辑的条件判断,必须放在锁内,是为了避免线程在等锁的过程中单例已产生 if cls._instance is None: # 通过super函数调用父元类type的__call__方法完成实例化 cls._instance = super(Singleton, cls).__call__(*args, **kwargs) return cls._instance # # 写法2 # # 元类属性_instances保存了所有单例类的实例,各单例类本身没有保存单例,各单例类也不会继承元类属性 # class Singleton(type): # _instances = dict() # _instance_lock = threading.Lock() # # def __call__(cls, *args, **kwargs): # if cls not in cls._instances.keys(): # with Singleton._instance_lock: # if cls not in cls._instances.keys(): # cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) # return cls._instances[cls] class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() class MyClass(OtherClass, metaclass=Singleton): class_attribute = 'class_default' def __init__(self): time.sleep(1) super(MyClass, self).__init__() self.x = 'x_default' @classmethod def class_func(cls): print('class function')输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1, id(obj): 39340128 arg: 1, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 2, id(obj): 39340128 arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, id(obj): 39340128 arg: 3, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, id(obj): 39340128 arg: 4, before: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, after: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, id(obj): 39340128 arg: 5, before: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 5, after: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, id(obj): 39340128 arg: 6, before: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 6, after: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, id(obj): 39340128 arg: 7, before: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 7, after: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, id(obj): 39340128 arg: 8, before: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, after: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, id(obj): 39340128 arg: 9, before: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, after: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, id(obj): 39340128 arg: 10, before: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, after: {‘a’: ‘a_10’, ‘x’: ‘x_10’}MyClass_________ MyClass: <class ‘singleton_class.MyClass’>, type(MyClass): <class ‘singleton_class.Singleton’> MyClass.class_attribute(): class_default class function arg: 1, id(obj): 39340128 arg: 1, before: {‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39340128 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.MyClass’> arg: 3, id(obj): 39340128 arg: 3, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’}SubClass_________ SubClass: <class ‘__ main__.SubClass’>, type(SubClass): <class ‘singleton_class.Singleton’> SubClass.class_attribute(): class_default class function arg: 11, id(obj): 39982808 arg: 11, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’, ‘y’: ‘y_default’} arg: 11, after: {‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, id(obj): 39982808 arg: 12, before: {‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, after: {‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} type(sub_obj): <class ‘__ main__.SubClass’> arg: 13, id(obj): 39982808 arg: 13, before: {‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} arg: 13, after: {‘a’: ‘a_13’, ‘x’: ‘x_13’, ‘y’: ‘y_13’} 优点:
将单例模式的代码独立封装,MyClass及其子类SubClass无需关心单例模式的实现MyClass类有继承的基类OtherClass时不影响单例效果单例模式不影响MyClass类作为基类被继承,且子类SubClass也是单例模式,即SubClass每次实例化得到都是同一个SubClass实例变量MyClass代表的是真正的MyClass类,能使用类属性、类方法type(obj) 返回的是真正的MyClass类通过obj3 = type(obj1)() 得到的实例也是单例,单例效果稳定有 lazy loading 效果缺点:
需手动设置双重校验锁,才能在保证多线程并发环境下得到的也是单例上述7种实现方式都是通过确保只有一个实例存在,从而实现单态的,而Borg模式的思路是"实例的唯一性并不是重要的,我们应该关注的是实例的状态,只要所有的实例共享状态,行为一致,那就达到了单例的目的"。通过Borg模式,可以创建任意数量的实例,但因为它们共享状态,从而实现了单态。所以严格来说,Borg模式不是单例模式,而是单态模式。
Borg模式代码的核心是,将所有实例的属性字典都指向同一个内存地址,这样就能实现虽然实例有多个,但属性字典只有一个,从而所有的实例共享状态。
需要注意的是,实例可以有多个,所以__new__方法的调用不限次数;但初始化成员变量只能有一次,所以__init__方法只能调用一次。由于元类的__call__方法能够控制这两个方法的调用,所以采用元类封装Borg模式的代码。
import threading import time class Singleton(type): _instance_lock = threading.Lock() # 元类的__init__方法负责在类创建后初始化类属性 def __init__(cls, *args, **kwargs): cls._shared_state = dict() cls._initialed = False super(Singleton, cls).__init__(*args, **kwargs) def __call__(cls, *args, **kwargs): obj = cls.__new__(cls, *args, **kwargs) # 将所有实例的属性字典都指向同一个内存地址,虽然实例有多个,但属性字典只有一个,从而实现所有实例共享状态 obj.__dict__ = cls._shared_state if not cls._initialed and obj is not None and isinstance(obj, cls): with Singleton._instance_lock: if not cls._initialed and obj is not None and isinstance(obj, cls): obj.__init__(*args, **kwargs) cls._initialed = True return obj class OtherClass(object): def __new__(cls): return super(OtherClass, cls).__new__(cls) def __init__(self): self.a = 'a_default' super(OtherClass, self).__init__() class MyClass(OtherClass, metaclass=Singleton): class_attribute = 'class_attribute' def __init__(self): super(MyClass, self).__init__() time.sleep(1) self.x = 'x_default' @classmethod def class_func(cls): print('class function')输出: _____________________________ MyClass MultiThreading Test______________________________________ arg: 1, id(obj): 40301288 arg: 1, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 40302072 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, id(obj): 40302296 arg: 3, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, id(obj): 40302520 arg: 5, id(obj): 40302744 arg: 5, before: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 4, before: {‘a’: ‘a_3’, ‘x’: ‘x_3’} arg: 6, id(obj): 40302968 arg: 4, after: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 6, before: {‘a’: ‘a_4’, ‘x’: ‘x_4’} arg: 6, after: {‘a’: ‘a_6’, ‘x’: ‘x_6’} arg: 5, after: {‘a’: ‘a_5’, ‘x’: ‘x_5’} arg: 7, id(obj): 40303192 arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 7, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 7, after: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, id(obj): 40303416 arg: 8, before: {‘a’: ‘a_7’, ‘x’: ‘x_7’} arg: 8, after: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, id(obj): 40303640 arg: 9, before: {‘a’: ‘a_8’, ‘x’: ‘x_8’} arg: 9, after: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, id(obj): 40303864 arg: 10, before: {‘a’: ‘a_9’, ‘x’: ‘x_9’} arg: 10, after: {‘a’: ‘a_10’, ‘x’: ‘x_10’} _____________________________ MyClass______________________________________ MyClass: <class ‘singleton_class.MyClass’>, type(MyClass): <class ‘singleton_class.Singleton’> MyClass.class_attribute(): class_attribute class function arg: 1, id(obj): 39514800 arg: 1, before: {‘a’: ‘a_10’, ‘x’: ‘x_10’} arg: 1, after: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, id(obj): 39945160 arg: 2, before: {‘a’: ‘a_1’, ‘x’: ‘x_1’} arg: 2, after: {‘a’: ‘a_2’, ‘x’: ‘x_2’} type(obj): <class ‘singleton_class.MyClass’> arg: 3, id(obj): 39667864 arg: 3, before: {‘a’: ‘a_2’, ‘x’: ‘x_2’} arg: 3, after: {‘a’: ‘a_3’, ‘x’: ‘x_3’} _____________________________ SubClass______________________________________ SubClass: <class ‘__ main__.SubClass’>, type(SubClass): <class ‘singleton_class.Singleton’> SubClass.class_attribute(): class_attribute class function arg: 11, id(obj): 40303584 arg: 11, before: {‘a’: ‘a_default’, ‘x’: ‘x_default’, ‘y’: ‘y_default’} arg: 11, after: {‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, id(obj): 40303360 arg: 12, before: {‘a’: ‘a_11’, ‘x’: ‘x_11’, ‘y’: ‘y_11’} arg: 12, after: {‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} type(sub_obj): <class ‘__ main__.SubClass’> arg: 13, id(obj): 40303248 arg: 13, before: {‘a’: ‘a_12’, ‘x’: ‘x_12’, ‘y’: ‘y_12’} arg: 13, after: {‘a’: ‘a_13’, ‘x’: ‘x_13’, ‘y’: ‘y_13’}
优点:
将单态模式的代码独立封装,MyClass及其子类SubClass无需关心单态模式的实现MyClass类有继承的基类OtherClass时不影响单态效果单态模式不影响MyClass类作为基类被继承,且子类SubClass也是单态模式,即SubClass的所有实例都共享SubClass的单态变量MyClass代表的是真正的MyClass类,能使用类属性、类方法type(obj) 返回的是真正的MyClass类通过obj3 = type(obj1)() 得到的实例也是单态有 lazy loading 效果缺点:
虽然所有实例的属性都指向同一个内存地址,但每个实例本身都分配了一个内存地址,这也是一种资源浪费需手动设置双重校验锁,才能在保证多线程并发环境下得到的也是单态