单例模式
单例模式 -- 所谓单例模式,就是说任何时候只有一个对象实例存在。也即不管实例化一个类多少次,真正干活的对象只会生成一次且在首次实例化时生成。也即固定类属性和方法。
1、使用嵌套类实现
在定义类A时,在类中再定义一个嵌套类_A。当对类A进行实例化时,将类_A的实例赋值给类A的属性_instance,然后给类A的实例定义一个__getattr__方法,是的类A调用自身方法、属性时都去调用类的_instance属性,也就是用类_A的实例的属性和方法。 类的属性是固定不变的,所以类A的实例虽然不同,但用的属性和方法是一样的。
class Singleton: ''' 单例模式 ''' # 创建一个嵌套类 class _A: def display(self): # 1创建一个嵌套类 _A,在类内部定义一个 display 方法,该方法返回 _A 类的实例的内存地址 return id(self) _instance = None def __init__(self): # 2编写 Singleton 类的实例的初始化方法。创建 Singleton 类的实例后,执行此方法。方法内部是对类的操作,为类的 _instance 属性赋值一个 _A 的实例。第一次对 Singleton 进行实例化时会创建一个 _A 类的实例并赋值,以后不再变化。 __class__._instance = __class__._instance or __class__._A() def __getattr__(self, attr): # 3 编写 Singleton 类的实例获取属性的方法。Singleton 类内部故意不为自身的实例设置任何属性,结果就是调用实例的属性时最后落到此方法的头上。方法内部获取类属性 _instance 的同名属性,也就是 _A 类的实例的属性。 return getattr(__class__._instance, attr) def __setattr__(self, attr, value): # 4编写 Singleton 类的实例定义属性的方法。同样,此方法内部调用 object.__setattr__ 方法为 Singleton._instance 也就是 _A 的实例定义属性。 object.__setattr__(__class__._instance, attr, value) if __name__ == '__main__': s1 = Singleton(); s2 = Singleton() # 5为 Singleton 类创建两个实例以备测试 print('id(s1):', id(s1)) # 6打印两个实例的内存地址,它们的结果应该是不同的 print('id(s2):', id(s2)) print('s1.display():', s1.display()) # 7打印两个实例调用 display 方法的结果,实际上调用的都是 Singleton._instance 的同名方法,结果应该是一样的 print('s2.display():', s2.display()) s1.name = 'James' # 8其中一个实例定义 name 属性,然后两个实例获取该属性并打印,结果应该都是一样的 print('s1.name:', s1.name) print('s2.name:', s2.name)
2、使用装饰器实现
首先创建一个[类装饰器],也就是编写一个类,这个类作为装饰器。这个[类装饰器]在实例化时将另一个类作为参数。类装饰器名称叫SingletonDeco,其__call__方法就是实例调用自身所执行的方法,我们可以把此方法的返回值定义为唯一的对象。
class SingletonDeco: """ 单例类装饰器 """ def __init__(self, cls): # 1类装饰器的初始化方法,将被装饰的类赋值给实例的 _cls 属性 print('装饰器初始化') self._cls = cls def instance(self): # 2 此方法用于给实例的 _instance 属性赋值,此方法的调用权交给了 __call__ 方法 try: return self._instance except AttributeError: self._instance = self._cls() return self._instance def __call__(self): # 3 类装饰器 SingletonDeco 的实例的调用接口 return self.instance() @SingletonDeco # 4用类装饰器创建 Singleton 类,创建该类时,会执行 SingletonDeco.__init__ 方法,并且将该类赋值给实例的 _cls 属性。此时 Singleton 这个变量就指向了 SingletonDeco 这个类的实例。 class Singleton: def display(self): return id(self) if __name__ == '__main__': s1 = Singleton() # 5用 Singleton ,表面上看是对 Singleton 类进行实例化,实际上是调用 SingletonDeco 类的实例的 __call__ 方法。 s2 = Singleton() print('id(s1):', s1.display()) print('id(s2):', s2.display()) print('s1 is s2:', s1 is s2)
3、重写new方法实现
对类实例化时,首先调用类的__new__方法创建实例,在调用实例的__init__方法初始化。所以要实现单例模式,可以再__new__做文章。
在__new__方法中返回一个类的实例即可,这样每次创建类的实例都会调用__new__方法,类属性是固定的。
class Singleton: def __new__(cls, *args, **kw): if not hasattr(cls, '_Singleton__instance'): # 1.利用hasattr属性判断__instance是否存在,不存在则创建 cls.__instance = super().__new__(cls, *args, **kw) print('实例化时打印实例 ID:', id(cls.__instance)) return cls.__instance s1 = Singleton() s2 = Singleton() print('s1 is s2:', s1 is s2)

浙公网安备 33010602011771号