單例模式
“單例”即在全局有且只有一個的實例,差不就類似於“全局變量”。
我個人常用類似以下的代碼來實現單例模式:
GLOBAL_KEY = '_my_coffee'
if GLOBAL_KEY not in globals():
# 初始化:
globals()[GLOBAL_KEY] = {
'cup_of': 'tea'
}
coff = globals()[GLOBAL_KEY]
print(coff['cup_of']) # Output: tea
上面的coff就是一個單例,全局僅會初始化一次,並總是同一個對象。
至於其他的實現方法,這裏不多做贅述。大家可以去看看站內的:Python中的單例模式的幾種實現方式的及優化
Any-singleton
大部分情況下,單例模式可以很容易得被實現,並且正確運行。但總是要寫一小段代碼來實現,就不那麼方便,也不易於管理。
為此,我就做了個簡易的單例模式工具庫——Any-singleton。
Any-singleton提供了兩大功能:“創建單例”和“使函數僅運行一次”。
創建單例
我們僅需要調用singleton()並傳入一個“唯一域名”和一個用於初始化的值,就可以很快的創建一個單例對象:
from any_singleton import singleton
tea = singleton('my_project.main.coffee', 'tea')
當然,也可以不直接給一個值,而是利用singleton()實例化一個對象作為單例的初始值:
from any_singleton import singleton
my_range = singleton('my_project.main.coffee', range, 123)
當第二個參數為一個type時,singleton()不會把該參數直接作為初始值,而是將其結合後面的參數實例化再作為初始值。
該單例的實例化過程在整個程序的生命週期將只會執行一次。
為了消除歧義,你還可以使用singleton_value()來替代singleton(),使之無論第二個參數是不是type類型的,都直接將其直接作為初始值使用:
from any_singleton import singleton_value
class Tea:
pass
tea = singleton_value('my_project.main.coffee', type(Tea))
使函數僅運行一次
使用@once()裝飾器來創建一個在整個程序生命週期裏只會被調用一次的函數:
import tomllib
from any_singleton import once, singleton
@once('my_project.initializations.init')
def init(config_path: str) -> None:
with open(config_path, 'rb') as f:
config = singleton('my_project.globals.config', tomllib.load(f))
init('config.toml')
或者使用@run_once()裝飾器來創建一個被@once()裝飾的函數,並立即自動調用一次。
import tomllib
from any_singleton import run_once, singleton
@run_once(
'my_project.initializations.init',
second_calling = SecondCallingBehaviour.NoneToReturn,
# 以下的參數將傳遞給被裝飾的`init()`。
'config.toml'
)
def init(config_path: str) -> None:
with open(config_path, 'rb') as f:
config = singleton('my_project.globals.config', tomllib.load(f))
基本的用法就是這些了。
更多內容可以去查看我已經在PyPI上發佈的any-singleton。