博客 / 詳情

返回

在Python中用any-singleton實現單例模式

單例模式

“單例”即在全局有且只有一個的實例,差不就類似於“全局變量”。

我個人常用類似以下的代碼來實現單例模式:

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。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.