1. 程式人生 > >python的單例模式

python的單例模式

__init__ ext ray 概念 port 程序 設計 eight 軟件設計

單例模式(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. class MyClass(Singleton):
    13. a = 1
    14. one = MyClass()
    15. two = MyClass()
    16. two.a = 3
    17. print one.a
    18. #3
    19. #one和two完全相同,可以用id(), ==, is檢測
    20. print id(one)
    21. #29097904
    22. print id(two)
    23. #29097904
    24. print one == two
    25. #True
    26. print one is two
    27. #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. class MyClass2(Borg):
      14. a = 1
      15. one = MyClass2()
      16. two = MyClass2()
      17. #one和two是兩個不同的對象,id, ==, is對比結果可看出
      18. two.a = 3
      19. print one.a
      20. #3
      21. print id(one)
      22. #28873680
      23. print id(two)
      24. #28873712
      25. print one == two
      26. #False
      27. print one is two
      28. #False
      29. #但是one和two具有相同的(同一個__dict__屬性),見:
      30. print id(one.__dict__)
      31. #30104000
      32. print id(two.__dict__)
      33. #30104000
      34. print ‘----------------------方法3--------------------------‘
      35. #方法3:本質上是方法1的升級(或者說高級)版
      36. #使用__metaclass__(元類)的高級python用法
      37. class Singleton2(type):
      38. def __init__(cls, name, bases, dict):
      39. super(Singleton2, cls).__init__(name, bases, dict)
      40. cls._instance = None
      41. def __call__(cls, *args, **kw):
      42. if cls._instance is None:
      43. cls._instance = super(Singleton2, cls).__call__(*args, **kw)
      44. return cls._instance
      45. class MyClass3(object):
      46. __metaclass__ = Singleton2
      47. one = MyClass3()
      48. two = MyClass3()
      49. two.a = 3
      50. print one.a
      51. #3
      52. print id(one)
      53. #31495472
      54. print id(two)
      55. #31495472
      56. print one == two
      57. #True
      58. print one is two
      59. #True
      60. print ‘----------------------方法4--------------------------‘
      61. #方法4:也是方法1的升級(高級)版本,
      62. #使用裝飾器(decorator),
      63. #這是一種更pythonic,更elegant的方法,
      64. #單例類本身根本不知道自己是單例的,因為他本身(自己的代碼)並不是單例的
      65. def singleton(cls, *args, **kw):
      66. instances = {}
      67. def _singleton():
      68. if cls not in instances:
      69. instances[cls] = cls(*args, **kw)
      70. return instances[cls]
      71. return _singleton
      72. @singleton
      73. class MyClass4(object):
      74. a = 1
      75. def __init__(self, x=0):
      76. self.x = x
      77. one = MyClass4()
      78. two = MyClass4()
      79. two.a = 3
      80. print one.a
      81. #3
      82. print id(one)
      83. #29660784
      84. print id(two)
      85. #29660784
      86. print one == two
      87. #True
      88. print one is two
      89. #True
      90. one.x = 1
      91. print one.x
      92. #1
      93. print two.x

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

          1. 單例模式

            單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。

            比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息。如果在程序運行期間,有很多地方都需要使用配置文件的內容,也就是說,很多地方都需要創建 AppConfig 對象的實例,這就導致系統中存在多個 AppConfig 的實例對象,而這樣會嚴重浪費內存資源,尤其是在配置文件內容很多的情況下。事實上,類似 AppConfig 這樣的類,我們希望在程序運行期間只存在一個實例對象。

            在 Python 中,我們可以用多種方法來實現單例模式:

            • 使用模塊
            • 使用 __new__
            • 使用裝飾器(decorator)
            • 使用元類(metaclass)

            使用模塊

            其實,Python 的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成 .pyc 文件,當第二次導入時,就會直接加載 .pyc 文件,而不會再次執行模塊代碼。因此,我們只需把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了。如果我們真的想要一個單例類,可以考慮這樣做:

            1 2 3 4 5 6 # mysingleton.py class My_Singleton(object): def foo(self): pass my_singleton = My_Singleton()

            將上面的代碼保存在文件 mysingleton.py 中,然後這樣使用:

            1 2 3 from mysingleton import my_singleton my_singleton.foo()

            使用 __new__

            為了使類只能出現一個實例,我們可以使用 __new__ 來控制實例的創建過程,代碼如下:

            1 2 3 4 5 6 7 8 9 class Singleton(object): _instance = None def __new__(cls, *args, **kw): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kw) return cls._instance class MyClass(Singleton): a = 1

            在上面的代碼中,我們將類的實例和一個類變量 _instance 關聯起來,如果 cls._instance 為 None 則創建實例,否則直接返回 cls._instance

            執行情況如下:

            1 2 3 4 5 6 7 8 >>> one = MyClass() >>> two = MyClass() >>> one == two True >>> one is two True >>> id(one), id(two) (4303862608, 4303862608)

            使用裝飾器

            我們知道,裝飾器(decorator)可以動態地修改一個類或函數的功能。這裏,我們也可以使用裝飾器來裝飾某個類,使其只能生成一個實例,代碼如下:

            1 2 3 4 5 6 7 8 9 10 11 12 13 14 from functools import wraps def singleton(cls): instances = {} @wraps(cls) def getinstance(*args, **kw): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance @singleton class MyClass(object): a = 1

            在上面,我們定義了一個裝飾器 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的單例模式