python实现单例模式

1、什么是单例模式:

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

  先看下面一个例子:

    

  可以看到,我调用了两次Marry实例化,得到的结果id是不同的,说明,两次创建了两个不同的Marry实例。

  所以如果我们想要让类有且仅有一个实例,思路就是创建一个实例,后续再创建的时候,先判断是否已经存在实例了,如果已经存在了,就直接引用之前创建的实例即可。

2、使用python实现单例模式

  方法一:这是最好理解的一种方法

  使用python模块--------python模块就是天然的单例模式。

  python模块在第一次导入时,会生成 .pyc 文件,第二次导入时,会直接加载 .pyc 文件,而不会再次执行模块代码。所以我们可以将需要单例模式的类定义在一个模块中。

  新建文件singleton.py

  在文件中实现如下方法:

    

  然后在需要使用实例的地方导入实例marry

  from singleton import marry

  看下面的测试结果,我多次导入了marry,打印id,发现他们是一样的,说明Marry实例只创建了一次。

  

  方法二:使用__new__来实现

  要理解这种方式,首先需要知道,创建一个类的实例的过程,先执行了类的__new__方法(通常我们没写,是默认调用了object的__new__方法),实例化对象,然后再调用__init__方法对对象进行初始化。

  

  如上图,我们在类Marry的__new__方法中,判断了,如果Marry的实例对象已经存在,则直接返回,反之才创建对象。

  但是上面的这种方式会有一点问题,就是在多线程中会出现问题,如下:

  方法三:使用装饰器实现单例模式

  

  方法四:使用元类

  首先需要理解什么是元类?下面来简单介绍一下:

  元类就是可以创建类的类

  我们正常创建一个类的时候是这样的:

  class Marry(Person):

    pass

  在创建Marry类的时候,python做了如下事情:

    1)在Marry中查找是否有__metaclass__这个属性,如果有,那么python会在内存中通过__metaclass__创建一个名为Marry的类对象

    2)Marry中没有找到__metaclass__属性,则回去她的父类Person中查找,并尝试用__metaclass__指定的方法创建一个Marry类对象

    3)如果任何一个父类中都没有__metaclass__属性,python会去模块中搜索是否有__metaclass__的指定。

    4)如果以上都没有,那么python会使用元类type来创建Marry

  我们要使用元类来实现单例模式,就是要自定义一个元类。

  自定义元类的目的,就是拦截类的创建,修改一些特性,然后再返回该类。听起来是不是和装饰器很相似?

  下面言归正传,看看通过元类来实现单例模式的代码:

 1 class SingletonType(type):
 2     def __call__(cls,*args, **kwargs):# 这里的cls即是Marry类
 3         if not hasattr(cls, "_instance"):
 4             cls._instance = super(SingletonType, self).__call__(*args, **kwargs)#type的__call__方法会调用Marry的__new__方法创建对象,然后调用__init__初始化对象
 5         return cls._instance
 6 
 7 
 8 class Marry(metaclass=SingletonType):#指定Marry的type为SingletonType
 9     def __init__(self):
10         self.name = "marry"
11         self.age = 25
12 
13 marry1 = Marry()
14 marry2 = Marry()

上面通过元类的方式实现了单例模式,创建了两个Marry实例,通过打印marry1和marry2的id,可以看到,他们的id是一样的,说明他们是同一个实例。

简单说一下上面元类实现单例模式的过程:

  1)类由type创建,创建类时,type的__init__会自动执行。类()执行type的__call__方法(即类的__new__方法和类的__init__方法)

  2)对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的__call__方法

  再看上面的例子:

  1)创建类Marry时,指定了元类为SingletonType(metaclass=SingletonType),此时会自动执行元类的__init__方法,class SingletonType中我们没有写__init__,但是它继承了type,所以它会自动执行type的__init__方法。

  2)实例化Marry(marry1=Marry())时,会去执行元类的__call__方法,在SingletonType的__call__方法中,我们判断了cls是否已经包含了实例,如果已经包含了,直接返回类的实例,如果没有包含,我们会调用type的__call__方法去创建实例。

  3)type的__call__方法中会调用cls的__new__方法去创建对象和__init__方法去初始化对象。

  4)如果我们给class Marry中加上__call__(cls, *args, **kwargs)方法,我们在调用实例marry1()的时候,会去调用Marry的__call__方法。

参考:https://www.cnblogs.com/huchong/p/8244279.html#navigator

原文地址:https://www.cnblogs.com/fiona-zhong/p/10365134.html