使用模塊
其實(shí)殖告,Python 的模塊就是天然的單例模式,因?yàn)槟K在第一次導(dǎo)入時雳锋,會生成 .pyc 文件黄绩,
當(dāng)?shù)诙螌?dǎo)入時,就會直接加載 .pyc 文件玷过,而不會再次執(zhí)行模塊代碼爽丹。
因此,我們只需把相關(guān)的函數(shù)和數(shù)據(jù)定義在一個模塊中辛蚊,就可以獲得一個單例對象了粤蝎。
如果我們真的想要一個單例類,可以考慮這樣做
1.創(chuàng)建test1.py文件,添加以下代碼
class Sington:
def __init__(self,*args,**kwargs):
self.name = args[0]
self.age = kwargs["age"]
sington = Sington("nick",age=23)
2.創(chuàng)建test2.py文件,在test2.py文件里面導(dǎo)入test1.py文件里面的sington
from test1 import sington
print(sington.name)
使用裝飾器實(shí)現(xiàn)單例模式
代碼如下:代碼的思想就是在裝飾器里面放一個字典,這個字典會存放所有需要使用單例模式的類的映射.
當(dāng)不存在映射時,就創(chuàng)建一個對象進(jìn)去,存在就略過
from functools import wraps
def sington(cls):
_instances = {}
@wraps(cls)
def wrapper(*args,**kwargs):
if cls not in _instances:
_instances[cls] = cls(*args,**kwargs)
return _instances[cls]
return wrapper
@sington
class Test:
def __init__(self,*args,**kwargs):
pass
test1 = Test()
test2 = Test()
print(id(test1) == id(test2)) # True
使用類的方式 (保證線程安全)
有陷阱的創(chuàng)建方式: 線程不安全
# 由于實(shí)例化對象的時候先調(diào)用__new__方法,再調(diào)用__init__方法,如果__init__出現(xiàn)耗時操作,比如數(shù)據(jù)庫連接
# 讀取文本之類的,就會造成多線程并發(fā)的情況下(時間片輪轉(zhuǎn))多個線程同時調(diào)用了instance方法.
# 就會造成多個對象出來,雖然最后一個執(zhí)行完的線程制造的對象會覆蓋掉之前創(chuàng)建的對象,
# 但依然是不安全的
import threading
import time
class Singleton(object):
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task():
obj = Singleton.instance()
print(id(obj))
for i in range(10):
t = threading.Thread(target=task)
t.start()
解決方法:枷鎖
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task():
obj = Singleton.instance()
print(id(obj))
list1 = list()
for i in range(10):
t = threading.Thread(target=task)
t.start()
list1.append(t)
for i in list1:
i.join()
obj = Singleton.instance()
print(obj)
方式三:基于new的線程安全
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = object.__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
def task():
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task)
t.start()