python的单例模式

Posted 谷永辉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python的单例模式相关的知识,希望对你有一定的参考价值。

单例模式(Singleton Pattern),是一种软件设计模式,是类只能实例化一个对象,

    目的是便于外界的访问,节约系统资源,如果希望系统中 只有一个对象可以访问,就用单例模式,

    显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

在 Python 中,我们可以用多种方法来实现单例模式:

  • 使用模块
  • 使用 __new__
  • 使用装饰器(decorator)
  • 使用元类(metaclass)

概念

简单说,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)

 

例子:

一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中我只有一个打印程序的实例。

 

代码

import threading

 

class Signleton(object):

    def __init__(self):

        print("__init__ method called")

 

    def __new__(cls):

        print("__new__ method called")

        mutex=threading.Lock()

        mutex.acquire() # 上锁,防止多线程下出问题

        if not hasattr(cls, ‘instance‘):

            cls.instance = super(LogSignleton, cls).__new__(cls)

        mutex.release()

        return cls.instance

 

if __name__ == ‘__main__‘:

obj = Signleton()

 

输出结果:

>>> ================================ RESTART ================================

>>>

__new__ method called

__init__ method called

>>> 

 

说明

1.从输出结果来看,最先调用 __new__ 方法,然后调用__init__方法

2. __new__ 通常用于控制生成一个新实例的过程,它是类级别的方法。

3. __init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性,做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。

 

 

 

方法1;

  __new__ 在__init__初始化前,就已经实例化对象,可以利用这个方法实现单例模式。

    1. print ‘----------------------方法1--------------------------‘  
    2. #方法1,实现__new__方法  
    3. #并在将一个类的实例绑定到类变量_instance上,  
    4. #如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回  
    5. #如果cls._instance不为None,直接返回cls._instance  
    6. class Singleton(object):  
    7.     def __new__(cls, *args, **kw):  
    8.         if not hasattr(cls, ‘_instance‘):  
    9.             orig = super(Singleton, cls)  
    10.             cls._instance = orig.__new__(cls, *args, **kw)  
    11.         return cls._instance  
    12.   
    13. class MyClass(Singleton):  
    14.     a = 1  
    15.   
    16. one = MyClass()  
    17. two = MyClass()  
    18.   
    19. two.a = 3  
    20. print one.a  
    21. #3  
    22. #one和two完全相同,可以用id(), ==, is检测  
    23. print id(one)  
    24. #29097904  
    25. print id(two)  
    26. #29097904  
    27. print one == two  
    28. #True  
    29. print one is two  
    30. #True 
      1. print ‘----------------------方法2--------------------------‘  
      2. #方法2,共享属性;所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法)  
      3. #同一个类的所有实例天然拥有相同的行为(方法),  
      4. #只需要保证同一个类的所有实例具有相同的状态(属性)即可  
      5. #所有实例共享属性的最简单最直接的方法就是__dict__属性指向(引用)同一个字典(dict)  
      6. #可参看:http://code.activestate.com/recipes/66531/  
      7. class Borg(object):  
      8.     _state = {}  
      9.     def __new__(cls, *args, **kw):  
      10.         ob = super(Borg, cls).__new__(cls, *args, **kw)  
      11.         ob.__dict__ = cls._state  
      12.         return ob  
      13.   
      14. class MyClass2(Borg):  
      15.     a = 1  
      16.   
      17. one = MyClass2()  
      18. two = MyClass2()  
      19.   
      20. #one和two是两个不同的对象,id, ==, is对比结果可看出  
      21. two.a = 3  
      22. print one.a  
      23. #3  
      24. print id(one)  
      25. #28873680  
      26. print id(two)  
      27. #28873712  
      28. print one == two  
      29. #False  
      30. print one is two  
      31. #False  
      32. #但是one和two具有相同的(同一个__dict__属性),见:  
      33. print id(one.__dict__)  
      34. #30104000  
      35. print id(two.__dict__)  
      36. #30104000  
      37.   
      38. print ‘----------------------方法3--------------------------‘  
      39. #方法3:本质上是方法1的升级(或者说高级)版  
      40. #使用__metaclass__(元类)的高级python用法  
      41. class Singleton2(type):  
      42.     def __init__(cls, name, bases, dict):  
      43.         super(Singleton2, cls).__init__(name, bases, dict)  
      44.         cls._instance = None  
      45.     def __call__(cls, *args, **kw):  
      46.         if cls._instance is None:  
      47.             cls._instance = super(Singleton2, cls).__call__(*args, **kw)  
      48.         return cls._instance  
      49.   
      50. class MyClass3(object):  
      51.     __metaclass__ = Singleton2  
      52.   
      53. one = MyClass3()  
      54. two = MyClass3()  
      55.   
      56. two.a = 3  
      57. print one.a  
      58. #3  
      59. print id(one)  
      60. #31495472  
      61. print id(two)  
      62. #31495472  
      63. print one == two  
      64. #True  
      65. print one is two  
      66. #True  
      67.   
      68. print ‘----------------------方法4--------------------------‘  
      69. #方法4:也是方法1的升级(高级)版本,  
      70. #使用装饰器(decorator),  
      71. #这是一种更pythonic,更elegant的方法,  
      72. #单例类本身根本不知道自己是单例的,因为他本身(自己的代码)并不是单例的  
      73. def singleton(cls, *args, **kw):  
      74.     instances = {}  
      75.     def _singleton():  
      76.         if cls not in instances:  
      77.             instances[cls] = cls(*args, **kw)  
      78.         return instances[cls]  
      79.     return _singleton  
      80.  
      81. @singleton  
      82. class MyClass4(object):  
      83.     a = 1  
      84.     def __init__(self, x=0):  
      85.         self.x = x  
      86.   
      87. one = MyClass4()  
      88. two = MyClass4()  
      89.   
      90. two.a = 3  
      91. print one.a  
      92. #3  
      93. print id(one)  
      94. #29660784  
      95. print id(two)  
      96. #29660784  
      97. print one == two  
      98. #True  
      99. print one is two  
      100. #True  
      101. one.x = 1  
      102. print one.x  
      103. #1  
      104. print two.x

        ==========================================================

          1. 单例模式

            单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

            比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

            在 Python 中,我们可以用多种方法来实现单例模式:

            • 使用模块
            • 使用 __new__
            • 使用装饰器(decorator)
            • 使用元类(metaclass)

            使用模块

            其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

            将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

            使用 __new__

            为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

            在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance

            执行情况如下:

            使用装饰器

            我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:

            在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]

            使用 metaclass

            元类(metaclass)可以控制类的创建过程,它主要做三件事:

            • 拦截类的创建
            • 修改类的定义
            • 返回修改后的类

            使用元类实现单例模式的代码如下:

             
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            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]
             
            # Python2
            class MyClass(object):
                __metaclass__ = Singleton
             
            # Python3
            # class MyClass(metaclass=Singleton):
            #    pass


以上是关于python的单例模式的主要内容,如果未能解决你的问题,请参考以下文章

Python中的单例模式

性能比较好的单例写法

Python中的单例模式——装饰器实现剖析

Python中的单例模式与反弹机制

Python中的单例模式

python的单例模式: