一、什么是单例模式?
""" 单例模式: 单例模式是一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象, 都是指向同一个内存地址,仅仅只有一个实例(对象)! 五种单例: - 模块 - 装饰器 - 元类 - __new__ - 类方法: classmethod """
二、单例模式的实现
1.通过类方法实现单例模式
''' 方式一: @classmethod ---> 通过类方法来实现单例 ''' class Foo(object): # 定义了一个类的数据属性, # 用于接收对象的实例,判断对象的实例是否只有一个 _instance = None # obj1 def __init__(self, name, age): self.name = name self.age = age @classmethod def singleton(cls, *args, **kwargs): # 判断类属性_instance是否有值,有代表已经有实例对象 # 没有则代表没有实例对象,则调用object的__init__获取实例对象 if not cls._instance: # object.__new__(cls): 创造对象 # 没有参数情况下 # cls._instance = object.__new__(cls, *args, **kwargs) # 有参数的情况下 cls._instance = cls(*args, **kwargs) # 相当于Foo() # 将已经产生的实例对象 直接返回 return cls._instance obj1 = Foo.singleton('yessir', '123') obj2 = Foo.singleton('yessir', '123') # print(obj1 is obj2)
2.通过元类实现单例模式
''' 方式二: 元类 ''' class MyMeta(type): # 1、先触发元类里面的__init__ def __init__(self, name, base, attrs): # self --> Goo # *** 造空的对象, 然后赋值给了Goo类中的_instance类属性 self._instance = object.__new__(self) # 将类名、基类、类的名称空间,传给type里面的__init__ super().__init__(name, base, attrs) # type.__init__(self, name, base, attrs) # 2、当调用Goo类时,等同于调用了由元类实例化的到的对象 def __call__(self, *args, **kwargs): # 判断调用Goo时是否传参 if args or kwargs: init_args = args init_kwargs = kwargs # 1)通过判断限制了用于传入的参数必须一致,然后返回同一个对象实例 if init_args == args and init_kwargs == kwargs: return self._instance # 2) 若不是同一个实例,则新建一个对象,产生新的内存地址 obj = object.__new__(self) self.__init__(obj, *args, **kwargs) return obj return self._instance class Goo(metaclass=MyMeta): # Goo = MyMeta(Goo) # _instance = obj def __init__(self, x): self.x = x g1 = Goo('1') g2 = Goo('1') # print(g1 is g2) # True
3.通过__new__方法实现单例模式
''' 方式三: __new__实现 ---> 通过调用类方法实例化对象时,自动触发的__new__来实现单例 ''' class Aoo(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = object.__new__(cls) return cls._instance a1 = Aoo() a2 = Aoo() # print(a1 is a2) # True
4.通过装饰器实现单例模式
''' 方式四: 装饰器实现 ---> 通过调用类方法实例化对象时,自动触发的__new__来实现单例 ''' # 单例装饰器 def singleton_wrapper(cls): # cls ---> Too # 因为装饰器可以给多个类使用,所以这里采用字典 # 以类作为key, 实例对象作为value值 _instance = { # 伪代码: 'Too': Too的示例对象 } def inner(*args, **kwargs): # 若当前装饰的类不在字典中,则实例化新类 # 判断当前装饰的Too类是否在字典中 if cls not in _instance: # obj = cls(*args, **kwargs) # return obj # 不在,则给字典添加 key为Too, value为Too()---> 实例对象 # {Too: Too(*args, **kwargs)} _instance[cls] = cls(*args, **kwargs) # return 对应的实例对象cls(*args, **kwargs) return _instance[cls] return inner @singleton_wrapper # singleton_wrapper(Too) class Too(object): pass t1 = Too() t2 = Too() # print(t1 is t2) # True
5.通过模块导入实现单例
''' 方式五: 模块导入实现 模块导入是天然的单例,也是最简单容易实现的一种方式 ''' import cls_singleton s1 = cls_singleton.instance s2 = cls_singleton.instance print(s1 is s2) # True
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/python/288363.html