python实现单例模式
一、什么是单例模式?
""" 单例模式: 单例模式是一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象, 都是指向同一个内存地址,仅仅只有一个实例(对象)! 五种单例: - 模块 - 装饰器 - 元类 - __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 hasattr(cls,'_instance'): 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): _instance = {} # 定义一个空字典,构造出{'Foo':Foo,'Aoo':Aoo,'Boo':Boo}这样的字典 def inner(*args,**kwargs): if cls not in _instance: _instance[cls] = cls(*args,**kwargs) return _instance[cls] # _instance['Foo']=Foo,此时的_instance={'Foo':Foo} return inner # inner=Foo,此时的_instance={'Foo':Foo} @singleton_wrapper # Foo = singoleton_wrapper(Foo) ==> Foo = inner class Foo(): pass s1 = Foo() # Foo()就是inner() s2 = Foo() print("s1",id(s1)) print("s2",id(s2)) print(s1 is s2) print(s1 == s2)
5.通过模块导入实现单例
''' 方式五: 模块导入实现 模块导入是天然的单例,也是最简单容易实现的一种方式 ''' import cls_singleton s1 = cls_singleton.instance s2 = cls_singleton.instance print(s1 is s2) # True