使用模塊
其實,Python 的模塊就是天然的單例模式,因爲模塊在第一次導入時,會生成 .pyc 文件,當第二次導入時,就會直接加載 .pyc 文件,而不會再次執行模塊代碼。因此,我們只需把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了。
class TestSingleton(object):
def test(self):
pass
test = TestSingleton()
使用 __new__
爲了使類只能出現一個實例,我們可以使用 __new__ 來控制實例的創建過程
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 Test(Singleton):
test = 111
print(id(Test()))
print(id(Test()))
print(id(Test()))
print(id(Test()))
139639721336784
139639721336784
139639721336784
139639721336784
使用裝飾器
裝飾器(decorator)可以動態地修改一個類或函數的功能。這裏,我們也可以使用裝飾器來裝飾某個類,使其只能生成一個實例
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 Test(object):
a = 111
在上面,我們定義了一個裝飾器 singleton,它返回了一個內部函數 getinstance,該函數會判斷某個類是否在字典 instances 中,如果不存在,則會將 cls 作爲 key,cls(*args, **kw) 作爲 value 存到 instances 中,否則,直接返回 instances[cls]。
使用 metaclass
元類(metaclass)可以控制類的創建過程,它主要做三件事:
- 攔截類的創建
- 修改類的定義
- 返回修改後的類
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 Test(object):
__metaclass__ = Singleton
''' Python3 '''
# class Test(metaclass=Singleton):
# pass