1. 程式人生 > >Python設計模式之單例模式

Python設計模式之單例模式

定義 eat size 字典 con gin 自動 super pytho

單例模式

單例模式需要註意的地方在於

  • 如何保證創建的實例是唯一的
  • 如何保證多線程情況下的訪問
  • 清晰明了

目前有這麽幾種方法:

  1. module
  2. metaclass
  3. __new__
  4. decorator

module

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

  1. 首先在一個py文件中定義這麽一個單例類:
class Singleton(object):
    def __init__(self
): self._val = 10 @property def val(self): return self._val @val.setter def val(self, val): self._val = val singleton = Singleton()
  1. 然後再在其它的文件中import
from Singleton import singleton
assert singleton.val == 10
singleton.val = 20
assert singleton.val == 20

但是這個有個缺點,就是程序一開始的時候就進行了創建,造成不必要的浪費,最好是在使用的時候才進行創建,還有另外一個缺點在於,如果有人不遵守規定使用已經創建好的實例而是自己創建則無法實現單例。

metaclass

這正是元類可以做的事情-通過聲明一個元類,我們告訴Python把類對象的創建路由到是我們提供的另一個類,從而達到攔截類的創建的目的。客戶唯一需要的是,它們需要聲明元類,每個這麽做的都會自動獲取到元類所提供的擴展。

class Singleton(type):
    def __init__(cls, what, bases, dict):
        super().__init__(what, bases, dict)
        cls._instance = None
    def __call__(cls, *args, **kwargs):
        if
cls._instance is None: cls._instance = super().__call__(*args, **kwargs) return cls._instance class MyClass(metaclass=Singleton): pass class1 = MyClass() class2 = MyClass() assert class1 == class2

__call__

如果在子類中如果沒有重載__new__方法,那麽子類則會順著繼承關系,找到父類中的__new__,但是如果子類已經重載了,而且沒有顯式的調用父類的方法,則相當於再次進行重載,就不會再去調用父類的__new__方法,需要註意!

class Singleton(object):
    _instance = None
    def __new__(cls, *more):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *more)
        return cls._instance
class MyClass(Singleton):
    pass
class1 = MyClass()
class2 = MyClass()
assert id(class1) == id(class2)

裝飾器

在裝飾器中,我們通過攔截它的__new__實現,判斷它是否存在於該類的__dict__字典中,如果存在則返回,不存在則創建該類並且存放於__dict__中,並且進行相應的初始化。

import functools
def singleton(cls):
    cls.__new_original__ = cls.__new__
    @functools.wraps(cls.__new__)
    def singleton_new(cls, *args, **kw):
        it = cls.__dict__.get(‘__it__‘)
        if it is not None:
            return it
        cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
        it.__init_original__(*args, **kw)
        return it
    cls.__new__ = singleton_new
    cls.__init_original__ = cls.__init__
    cls.__init__ = object.__init__
    return cls
@singleton
class myclass:
    pass
class1 = myclass()
class2 = myclass()
assert class1 == class2

Python設計模式之單例模式