单例模式

单例模式 -- 所谓单例模式,就是说任何时候只有一个对象实例存在。也即不管实例化一个类多少次,真正干活的对象只会生成一次且在首次实例化时生成。也即固定类属性和方法。

 

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)

 

posted @ 2021-07-09 11:17  宇宙刘  阅读(64)  评论(0)    收藏  举报