python3單例模式

2021-09-28 20:51:41 字數 4668 閱讀 4371

單例模式是某個類在整個系統中只存在乙個例項的一種設計模式。

使用單例模式的好處:

單例模式不僅可以減少記憶體資源占用,而且因為只初始化一次,還可以加快執行效能。例如當程式通過乙個類來讀取配置資訊,而程式多個地方需要使用配置資訊,這時整個程式執行過程中只需乙個例項物件即可,可減少占用記憶體資源,同時還可以保證程式在多處地方獲取的配置資訊一致。

使用單例模式可進行同步控制,計數器同步、程式多處讀取配置資訊這些情景下若只存在乙個例項,即可保證一致性。

python實現單例模式有4種方式:

通過模組呼叫

使用__new__方法

使用裝飾器

使用元類(metaclass) 

在python3中,首次匯入模組檔案時,會在程式目錄下的__pycache__目錄中生成pyc檔案,再匯入時,將直接載入pyc檔案。因此,只需把相關的函式和資料定義在乙個模組中,就可以獲得乙個單例物件了。 

class singleton_cal:

def foo(self)

pass

export_singleton = singleton_cal()

from singleton_demo import export_singleton

a = export_singleton

b = export_singleton

print(id(a) == id(b))

__new__:建立例項物件時呼叫的構造方法

當例項化乙個物件時,先呼叫__new__方法(未定義時呼叫object.__new__)例項化物件,然後呼叫__init__方法進行物件初始化。

所以,可以宣告乙個私有類變數__instance。當__instance不為none時,表示系統中已有例項,直接返回該例項;若__instance為none時,表示系統中還沒有該類的例項,則建立新例項並返回。

class singleton(object):

__instance = none

def __new__(cls, *args, **kwargs):

if not cls.__instance:

cls.__instance = super().__new__(cls, *args, **kwargs)

return cls.__instance

a = singleton()

b = singleton()

print(id(a) == id(b))

from functools import wraps

def singleton(cls):

instances = {}

@wraps(cls)

def get_instance(*args, **kwargs):

if cls not in instances:

instances[cls] = cls(*args, **kwargs)

return instances[cls]

return get_instance

@singleton

class singleton(object):

def foo(self):

pass

a = singleton()

b = singleton()

print(id(a) == id(b))

只有第一次呼叫singleton類時,裝飾器才會從instances={}開始執行,以後再呼叫該類時,都只執行get_instance函式,這是裝飾器的特性。

利用裝飾器的這個特性,可以實現單例模式。復用裝飾器,可以使多個類實現單例模式。

元類建立了所有的型別物件(包括object物件),系統預設的元類是type。

執行順序:先定義metaclass,然後在類定義時,通過metaclass建立類,最後通過定義好的類建立例項。

所以,metaclass允許你建立類或者修改類。換句話說,可以把類看成是metaclass建立出來的「例項」。

元類中定義的__new__方法,在以該類為元類的類定義時自動呼叫。例如:類a以類b為元類,當定義類a時,類b的__new__方法將會被自動呼叫。

元類中定義的__call__方法,在以該類為元類的類建立例項時自動呼叫。例如:類a以類b為元類,當類a建立例項時,類b的__call__方法將會被自動呼叫。

1、元類的使用

自定義元類時,通常繼承自type。

class metaclass(type):

def __init__(cls, *args, **kwargs):

# cls 代指以該類為元類的類 foo

super(metaclass, cls).__init__(*args, **kwargs)

def __new__(mcs, *args, **kwargs):

# mcs 代指元類自身

print("metaclass.__new__: ", mcs)

return super().__new__(mcs, *args, **kwargs)

def __call__(cls, *args, **kwargs):

# cls 代指以該類為元類的類 foo

print("cls: ", cls)

obj = cls.__new__(cls, *args, **kwargs)

cls.__init__(obj, *args, **kwargs)

return obj

class foo(metaclass=metaclass):

# 定義類foo時,將呼叫元類的__new__方法和__init__方法。就跟一般普通類例項化時呼叫__new__方法和__init__方法一樣。

def __init__(self, name):

self.name = name

# foo 例項化時會呼叫元類的__call__方法。

a = foo("abc")

2、元類實現單例模式宣告乙個私有變數__instance儲存類例項。__instance為none時,呼叫type的__call__方法為類建立例項。

class singletonmeta(type):

__instance = none

def __call__(cls, *args, **kwargs):

if not cls.__instance:

cls.__instance = type.__call__(cls, *args, **kwargs)

return cls.__instance

class myclass(metaclass=singletonmeta):

def foo(self):

pass

a = myclass()

b = myclass()

print(id(a) == id(b))

class singleton(object):

def __init__(self):

pass

@classmethod

def instance(cls, *args, **kwargs):

if not hasattr(singleton, "_instance"):

singleton._instance = singleton(*args, **kwargs)

return singleton._instance

執行緒安全通過以上方法定義的單例模式,無法支援多執行緒。解決這個問題的辦法是:加鎖!未加鎖部分併發執行,加鎖部分序列執行。

import threading

class singleton(object):

_instance_lock = threading.lock()

@classmethod

def instance(cls, *args, **kwargs):

if not hasattr(singleton, "_instance"):

with singleton._instance_lock:

singleton._instance = singleton(*args, **kwargs)

return singleton._instance

def task(arg):

obj = singleton.instance()

print("task {}".format(arg), id(obj))

for i in range(10):

t = threading.thread(target=task, args=[i,])

t.start()

使用類實現的單例模式,在使用時必須通過singleton.instance()進行例項化。如果使用singleton()進行例項化得到的不是單例。

Python3 單例模式問題

單例模式,也叫單子模式,是一種常用的軟體設計模式,屬於建立型模式的一種。在應用這個模式時,單例物件的類必須保證只有乙個例項存在。許多時候整個系統只需要擁有乙個的全域性物件,這樣有利於我們協調系統整體的行為。比如在某個伺服器程式中,該伺服器的配置資訊存放在乙個檔案中,這些配置資料由乙個單例物件統一讀取...

python3中的單例模式Singleton

usr bin env python coding utf 8 date 2019 01 21 09 09 09 author cdl 1217096231 qq.com link version id 單例模式singleton 一種常見的軟體設計模式,該模式的主要目的是確保某乙個類只有乙個例項存...

python3 魔術方法之單例模式(四)

class singleclass object instance 0def new cls,args,kwargs if not cls.instance cls.instance object new cls,args,kwargs return cls.instance return cls....