Python學習之——單例模式
- 參考
- 1 利用__metaclass__實現單例
- super的用法
- class Singleton(type)元類
- 2 重載__new__方法實現單例模式
- 3 利用裝飾器實現單例
- 考慮一個類如果繼承一個單例類的問題
參考
python之metaclass+singleton(一)
python之metaclass+singleton(二)
python之metaclass+singleton(三)
1 利用__metaclass__實現單例
揭開Python元類(metaclass)神秘的面紗
super的用法
【python】B站最細致的super()詳解,一定有你不知道的知識!
super(arg1):
一個參數:
# 返回一個未bind的對象
ubo = super(Male)
# bind一個object
ubo.__get__(self).__init__(age, name)super(arg1,arg2):
兩個參數:
arg1:決定從MRO鏈中的arg1后開始
arg2:決定使用該super函數的對象object和對象的MRO,注意arg2也可以是class,但不常用
class Singleton(type)元類
singleton文件夾
__ init__.py文件
# -*- coding: utf-8 -*-
"""單例."""class Singleton(type):def __init__(cls, name, bases, dict):super(Singleton, cls).__init__(name, bases, dict)cls.instance = Nonedef __call__(cls, *args, **kwargs):print 'call Singleton __call__'if cls.instance is None:# 等價于cls.instance = type.__call__(cls, *args, **kwargs)cls.instance = super(Singleton, cls).__call__(*args, **kwargs)return cls.instance
利用__metaclass__實現單例的示例
class Foo(object):__metaclass__ = Singletonfoo1 = Foo()
foo2 = Foo()
#運行結果應該為True, 但實際是False, 想想為啥會出現這樣的異常??
print foo1 is foo2
請思考如下問題:
-
不用Foo類去創建實例,僅僅只有Foo和Singleton定義,執行腳本,會不會像第二節中打印出print語句?
不會 -
__call__在哪里調用?
還記得__call__是怎么調用的嗎?是一個類實例化出來的對象obj,直接通過obj ()形式調用了 __ call __。
此處的元類根本沒有復寫 __new __和 __init __方法,Foo類就是Singleton創建出來的一個普通的類(就是一個Singleton類的對象,實例),因此Foo()會調用Singleton的 __call __。
__call__中限定了只能新建一個Foo類的對象。如果想要定義的類是單例的,只要定義類時指定__metaclass__ = Singleton即可。 -
繼承Foo類的也會是單例嗎?
class FooChild(Foo):def __init__(self, a):super(FooChild, self).__init__()
foo11 = FooChild()
foo22 = FooChild()
print foo11 is foo22 #運行結果為True
2 重載__new__方法實現單例模式
“雙重檢查鎖定”(Double-Checked Locking)單例模式
from threading import Lockclass SingletonClass(object):instance = Nonelock = Lock()def __new__(cls, *args, **kwargs):if cls.instance:return cls.instancewith cls.lock:# double checkif not cls.instance:cls.instance = super(SingletonClass, cls).__new__(cls, *args, **kwargs)return cls.instance# 測試
if __name__ == "__main__":s1 = SingletonClass()s2 = SingletonClass()print(s1 is s2) # 應該輸出 True# 在多線程環境中測試import threadingdef test_singleton():instance = SingletonClass()print(f"Instance id in thread {threading.current_thread().name}: {id(instance)}")threads = [threading.Thread(target=test_singleton) for _ in range(5)]for t in threads:t.start()for t in threads:t.join()
3 利用裝飾器實現單例
def singleton(cls):instances = {}def wrapper(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return wrapper@singleton
class Foo(object):passfoo1 = Foo()#等同于
#class Foo(object):
# pass
#foo1 = singleton(Foo)
foo2 = Foo()
print foo1 is foo2 #運行結果為True
考慮一個類如果繼承一個單例類的問題
3 中繼承會出現問題
# 報錯function() argument 'code' must be code, not str
# 因為Foo被裝飾后成為了函數而不是class
# class FooChild(Foo):# 改成如下
ClassFoo = Foo().__class__class FooChild(ClassFoo):def __init__(self, a=0):super(FooChild, self).__init__()
但是這里的 FooChild就不在是單例了,也沒法在加上@singleton來實現單例了