赞同 1
分享

【设计模式】- 单例

简介:单例模式我通常都是直接使用类方法__new__来控制创建次数,但其实还有其他更有意思的写法,这篇文章我验证了元类控制对象创建的方法的优点以及缺点。
  2021.04.08
  Bug Man
  1
  72
  172.17.0.1
  中国.上海
 
 

比较常见的new魔法方法函数控制单例

通过观察下方代码运行结果,可以看到两次实例化的对象时同一个内存地址。

class SingleInstance(object):
    __instance = None

    def __new__(cls, *args, **kwargs):
        print('__new__')
        if cls.__instance is None:
            if cls.__instance is None:
                cls.__instance = super(SingleInstance, cls).__new__(cls, *args, **kwargs)
        return cls.__instance

    def __init__(self):
        print('__init__')


if __name__ == '__main__':
    single = SingleInstance()
    single2 = SingleInstance()
    print(single, single2)
    # __new__
    # __init__
    # __new__
    # __init__
    # <__main__.SingleInstance object at 0x000000000499DEB0> <__main__.SingleInstance object at 0x000000000499DEB0>
使用元类控制单例

一句话概括什么是元类:所有使用type()动态创建的类/对象或者继承type的类都是一个元类,type就是Python在背后用来创建所有类的元类。详细了解元类推荐文章:Python 元类

元类的__new__魔法方法有一个特征:只执行一次。通过运行结果可以看到,确实只执行了一次,而且还是在解释器读取所有模块时执行,并不是在实例化时执行。除了这个特性得到了验证,我还发现了另外一个特性,如果元类没有返回新的对象实例时,继承这个元类的类将不执行__new____init__直接跳过实例化的过程。由于这个特性,所以每次都需要初始化的单例类就不适合使用元类来做单例的控制了,相反就可以使用元类来控制单例类。

class SingleInstanceType(type):
    __instance = None
    __count = 0

    def __new__(cls, *args, **kwargs):
        print('type __new__')
        return super(SingleInstanceType, cls).__new__(cls, *args, **kwargs)

    def __call__(self, *args, **kwargs):
        print('type __call__')
        self.__count += 1
        if self.__instance is None or self.__count == 5:
            self.__instance = super(SingleInstanceType, self).__call__(*args, **kwargs)
        return self.__instance


class SingleInstanceTypeObject(metaclass=SingleInstanceType):

    def __new__(cls, *args, **kwargs):
        print('obj __new__')
        return super(SingleInstanceTypeObject, cls).__new__(cls, *args, **kwargs)

    def __init__(self):
        print('obj __init__')


if __name__ == '__main__':
    single = SingleInstanceTypeObject()
    single2 = SingleInstanceTypeObject()
    single3 = SingleInstanceTypeObject()
    single4 = SingleInstanceTypeObject()
    single5 = SingleInstanceTypeObject()
    print(single, single2, single3)
    # type __new__
    # type __call__
    # obj __new__
    # obj __init__
    # type __call__
    # type __call__
    # type __call__
    # type __call__
    # obj __new__
    # obj __init__
    # <__main__.SingleInstanceTypeObject object at 0x0000000004A1F130> <__main__.SingleInstanceTypeObject object at 0x0000000004A1F130> <__main__.SingleInstanceTypeObject object at 0x0000000004A1F130>