python单例模式原理及实现

python单例模式的原理及实现

什么是单例模式:

单例模式即一个类有且仅有一个实例。

为什么要用:

全局变量,因为这比函数的参数传来传去更容易让人理解。确实在很多场景下用全局变量很方便。不过如果代码规模增大,并且有多个文件的时候,全局变量就会变得比较混乱。

你可能不知道在哪个文件中定义了相同类型甚至重名的全局变量,也不知道这个变量在程序的某个地方被做了怎样的操作。

单例模式保证了在程序的不同位置都可以且仅可以取到同一个对象实例:如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。因为单例是一个类,所以你也可以为其提供相应的操作方法,以便于对这个实例进行管理。

python中,一个类创建对象实例是通过调用父类object的 __new__(cls)方法来创建对象的,因此我们可以通过重写 __new__(cls)方法去实现类只创建一个实例

class Sun(object):
    __instance=None #定义一个类属性做判断
    def __new__(cls):
        if cls.__instance==None:
            #如果__instance为空证明是第一次创建实例
            #通过父类的__new__(cls)创建实例
            cls.__instance==object.__new__(cls)
            return cls.__instance
        else:
            #返回上一个对象的引用
            return cls.__instance
a = Sun()
print(id(a))
b = Sun()
print(id(b))

注意:

1)__new__方法是静态类方法,虽然没有加静态类方法的装饰器;

2)A继承object类,虽然通常可以省略object字样。但这里省略就无法执行__new__方法。若A继承其他类,同样可以使用object的__new__方法,也可以使用父类的__new__方法;

3)在实例化对象的时候,__new__方法在__init__方法之前执行;

4)__new__必须返回一个对象,才能给__init__初始化。

__init__初始化会影响属性的内容。在使用单例模式时,尽量避免初始化属性或者初始化属性之前先判断是否存在该属性。

使用函数装饰器实现单例

使用类装饰器实现单例

def singleton(cls):
    _instance = {}#使用不可变的类地址作为键,其实例作为值,每次创造实例时,
#首先查看该类是否存在实例,存在的话直接返回该实例即可,
#否则新建一个实例并存放在字典中。 def inner(): if cls not in _instance: _instance[cls] = cls() return _instance[cls] return inner @singleton class Cls(object): def __init__(self): pass cls1 = Cls() cls2 = Cls() print(id(cls1) == id(cls2))

使用 metaclass 实现单例模式

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Cls4(metaclass=Singleton):
    pass

cls1 = Cls4()
cls2 = Cls4()
print(id(cls1) == id(cls2))