摘要:看一下中這兩者以及的實現前面提到類相當于元類的實例化,再聯系創建單例模式時使用的函數,用的是,其實用三種中任何一種都是可以的,來看一下使用元類時各方法的調用情況結果元類的和只在創建類調用了一次,而創建的實例時,每次都會調用元類的方法
單例模式的實現方式
將類實例綁定到類變量上
class Singleton(object): _instance = None def __new__(cls, *args): if not isinstance(cls._instance, cls): cls._instance = super(Singleton, cls).__new__(cls, *args) return cls._instance
但是子類在繼承后可以重寫__new__以失去單例特性
class D(Singleton): def __new__(cls, *args): return super(D, cls).__new__(cls, *args)
使用裝飾器實現
def singleton(_cls): inst = {} def getinstance(*args, **kwargs): if _cls not in inst: inst[_cls] = _cls(*args, **kwargs) return inst[_cls] return getinstance @singleton class MyClass(object): pass
問題是這樣裝飾以后返回的不是類而是函數,當然你可以singleton里定義一個類來解決問題,但這樣就顯得很麻煩了
使用__metaclass__,這個方式最推薦
class Singleton(type): _inst = {} def __call__(cls, *args, **kwargs): if cls not in cls._inst: cls._inst[cls] = super(Singleton, cls).__call__(*args) return cls._inst[cls] class MyClass(object): __metaclass__ = Singletonmetaclass
元類就是用來創建類的東西,可以簡單把元類稱為“類工廠”,類是元類的實例。type就是Python的內建元類,type也是自己的元類,任何一個類
>>> type(MyClass) type >>> type(type) type
python在創建類MyClass的過程中,會在類的定義中尋找__metaclass__,如果存在則用其創建類MyClass,否則使用內建的type來創建類。對于類有繼承的情況,如果當前類沒有找到,會繼續在父類中尋找__metaclass__,直到所有父類中都沒有找到才使用type創建類。
如果模塊里有__metaclass__的全局變量的話,其中的類都將以其為元類
查看type的定義,
type(object) -> the object"s type
type(name, bases, dict) -> a new type
所以利用type定義一個類的元類,可以用函數返回一個上面第二種定義的對象,也可以繼承type并重寫其中的方法。
直接使用type生成的對象作為元類,函數作用是使屬性變為大寫
def update_(name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith("__")) uppercase_attr = {name.upper(): value for name, value in attrs} return type(name, bases, uppercase_attr) class Singleton(object): __metaclass__ = update_ abc = 2 d = Singleton() print d.ABC # 2
上一節中,單例模式元類實現用的是類繼承方式,而對于第一種__new__的方式,本質上調用的是type.__new__,不過使用super能使繼承更清晰一些并避免一些問題
這里簡單說明一下,__new__是在__init__前調用的方法,會創建對象并返回,而__init__則是用傳入的參數將對象初始化。看一下type中這兩者以及__call__的實現
def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__ """ type(object) -> the object"s type type(name, bases, dict) -> a new type # (copied from class doc) """ pass @staticmethod # known case of __new__ def __new__(S, *more): # real signature unknown; restored from __doc__ """ T.__new__(S, ...) -> a new object with type S, a subtype of T """ pass def __call__(self, *more): # real signature unknown; restored from __doc__ """ x.__call__(...) <==> x(...) """ pass
前面提到類相當于元類的實例化,再聯系創建單例模式時使用的函數,用的是__call__,其實用三種magic method中任何一種都是可以的,來看一下使用元類時各方法的調用情況
class Basic(type): def __new__(cls, name, bases, newattrs): print "new: %r %r %r %r" % (cls, name, bases, newattrs) return super(Basic, cls).__new__(cls, name, bases, newattrs) def __call__(self, *args): print "call: %r %r" % (self, args) return super(Basic, self).__call__(*args) def __init__(cls, name, bases, newattrs): print "init: %r %r %r %r" % (cls, name, bases, newattrs) super(Basic, cls).__init__(name, bases, dict) class Foo: __metaclass__ = Basic def __init__(self, *args, **kw): print "init: %r %r %r" % (self, args, kw) a = Foo("a") b = Foo("b")
結果
new:
"Foo" () {"__module__": "__main__", "__metaclass__": , "__init__": init at 0x106fd5320>}
init:"Foo" () {"__module__": "__main__", "__metaclass__": , "__init__": init at 0x106fd5320>}
call:("a",)
init: <__main__.Foo object at 0x106fee990> ("a",) {}
call:("b",)
init: <__main__.Foo object at 0x106feea50> ("b",) {}
元類的__init__和__new__只在創建類Foo調用了一次,而創建Foo的實例時,每次都會調用元類的__call__方法
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/45418.html
摘要:本篇文章總結了目前主流的實現單例模式的方法供讀者參考。使用實現單例模式同樣,我們在類的創建時進行干預,從而達到實現單例的目的。 很多初學者喜歡用 全局變量 ,因為這比函數的參數傳來傳去更容易讓人理解。確實在很多場景下用全局變量很方便。不過如果代碼規模增大,并且有多個文件的時候,全局變量就會變得比較混亂。你可能不知道在哪個文件中定義了相同類型甚至重名的全局變量,也不知道這個變量在程序的某...
摘要:在中,我們可以用多種方法來實現單例模式使用模塊使用使用裝飾器使用元類使用模塊其實,的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成文件,當第二次導入時,就會直接加載文件,而不會再次執行模塊代碼。 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對...
摘要:使用元類可以控制類的創建過程,它主要做三件事攔截類的創建修改類的定義返回修改后的類使用元類實現單例模式的代碼如下執行結果 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。 比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個 ...
摘要:實現實現單例模式有多種方案使用提供了非常易用的類,只要繼承它,就會成為單例。參考鏈接單例模式最后,感謝女朋友支持。 問題:現代化的巧克力工廠具備計算機控制的巧克力鍋爐。鍋爐做的事情就是把巧克力和牛奶融在一起,然后送到下一個階段,以制成巧克力棒。下邊是一個巧克力公司鍋爐控制器的代碼,仔細觀察一下,這段代碼有什么問題? class ChocolateBoiler(object): ...
摘要:最近在學習設計模式而開發的語言中比較中意的就是了在這里總結下設計模式一般分為三大類構造型結構型行為型先從創建型設計模式開始創建型設計模式包括單例模式抽象工廠模式工廠方法模式生成器模式惰性初始化模式對象池模式原型模式單例模式單例模式的定義是保 最近在學習設計模式,而開發的語言中比較中意的就是python了,在這里總結下. 設計模式一般分為三大類:構造型,結構型,行為型 先從創建型設計模式...
閱讀 1887·2021-09-27 13:35
閱讀 3434·2019-08-30 14:16
閱讀 2489·2019-08-30 10:52
閱讀 869·2019-08-29 16:35
閱讀 1422·2019-08-29 15:22
閱讀 3648·2019-08-23 18:21
閱讀 3139·2019-08-23 18:00
閱讀 3127·2019-08-23 16:50