zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    tudou(土豆)、youku(优酷)API(有相应的dll [C#])
    创新工场2012笔试编程捕鱼和分鱼
    区别Web文本框和HTML文本框的RandOnly、Disabled
    DataRow[]、List<DataRow>无法绑定到GridView的问题解决!
    1、NHibernate入门
    Verilog HDL 学习笔记2blocking and nonblocking assignment
    Verilog HDL 学习笔记1data type
    2006.08.21网摘
    推荐十一个很酷的实用网站
    类 ObjectOutputStream的writeObject()方法的中英文对照
  • 原文地址:https://www.cnblogs.com/fiona-zhong/p/10365134.html
Copyright © 2011-2022 走看看