摘要:看一下中這兩者以及的實(shí)現(xiàn)前面提到類相當(dāng)于元類的實(shí)例化,再聯(lián)系創(chuàng)建單例模式時(shí)使用的函數(shù),用的是,其實(shí)用三種中任何一種都是可以的,來(lái)看一下使用元類時(shí)各方法的調(diào)用情況結(jié)果元類的和只在創(chuàng)建類調(diào)用了一次,而創(chuàng)建的實(shí)例時(shí),每次都會(huì)調(diào)用元類的方法
單例模式的實(shí)現(xiàn)方式
將類實(shí)例綁定到類變量上
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)
使用裝飾器實(shí)現(xiàn)
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
問(wèn)題是這樣裝飾以后返回的不是類而是函數(shù),當(dāng)然你可以singleton里定義一個(gè)類來(lái)解決問(wèn)題,但這樣就顯得很麻煩了
使用__metaclass__,這個(gè)方式最推薦
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
元類就是用來(lái)創(chuàng)建類的東西,可以簡(jiǎn)單把元類稱為“類工廠”,類是元類的實(shí)例。type就是Python的內(nèi)建元類,type也是自己的元類,任何一個(gè)類
>>> type(MyClass) type >>> type(type) type
python在創(chuàng)建類MyClass的過(guò)程中,會(huì)在類的定義中尋找__metaclass__,如果存在則用其創(chuàng)建類MyClass,否則使用內(nèi)建的type來(lái)創(chuàng)建類。對(duì)于類有繼承的情況,如果當(dāng)前類沒(méi)有找到,會(huì)繼續(xù)在父類中尋找__metaclass__,直到所有父類中都沒(méi)有找到才使用type創(chuàng)建類。
如果模塊里有__metaclass__的全局變量的話,其中的類都將以其為元類
查看type的定義,
type(object) -> the object"s type
type(name, bases, dict) -> a new type
所以利用type定義一個(gè)類的元類,可以用函數(shù)返回一個(gè)上面第二種定義的對(duì)象,也可以繼承type并重寫其中的方法。
直接使用type生成的對(duì)象作為元類,函數(shù)作用是使屬性變?yōu)榇髮?/p>
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
上一節(jié)中,單例模式元類實(shí)現(xiàn)用的是類繼承方式,而對(duì)于第一種__new__的方式,本質(zhì)上調(diào)用的是type.__new__,不過(guò)使用super能使繼承更清晰一些并避免一些問(wèn)題
這里簡(jiǎn)單說(shuō)明一下,__new__是在__init__前調(diào)用的方法,會(huì)創(chuàng)建對(duì)象并返回,而__init__則是用傳入的參數(shù)將對(duì)象初始化。看一下type中這兩者以及__call__的實(shí)現(xiàn)
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
前面提到類相當(dāng)于元類的實(shí)例化,再聯(lián)系創(chuàng)建單例模式時(shí)使用的函數(shù),用的是__call__,其實(shí)用三種magic method中任何一種都是可以的,來(lái)看一下使用元類時(shí)各方法的調(diào)用情況
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")
結(jié)果
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__只在創(chuàng)建類Foo調(diào)用了一次,而創(chuàng)建Foo的實(shí)例時(shí),每次都會(huì)調(diào)用元類的__call__方法
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/45418.html
摘要:本篇文章總結(jié)了目前主流的實(shí)現(xiàn)單例模式的方法供讀者參考。使用實(shí)現(xiàn)單例模式同樣,我們?cè)陬惖膭?chuàng)建時(shí)進(jìn)行干預(yù),從而達(dá)到實(shí)現(xiàn)單例的目的。 很多初學(xué)者喜歡用 全局變量 ,因?yàn)檫@比函數(shù)的參數(shù)傳來(lái)傳去更容易讓人理解。確實(shí)在很多場(chǎng)景下用全局變量很方便。不過(guò)如果代碼規(guī)模增大,并且有多個(gè)文件的時(shí)候,全局變量就會(huì)變得比較混亂。你可能不知道在哪個(gè)文件中定義了相同類型甚至重名的全局變量,也不知道這個(gè)變量在程序的某...
摘要:在中,我們可以用多種方法來(lái)實(shí)現(xiàn)單例模式使用模塊使用使用裝飾器使用元類使用模塊其實(shí),的模塊就是天然的單例模式,因?yàn)槟K在第一次導(dǎo)入時(shí),會(huì)生成文件,當(dāng)?shù)诙螌?dǎo)入時(shí),就會(huì)直接加載文件,而不會(huì)再次執(zhí)行模塊代碼。 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設(shè)計(jì)模式,該模式的主要目的是確保某一個(gè)類只有一個(gè)實(shí)例存在。當(dāng)你希望在整個(gè)系統(tǒng)中,某個(gè)類只能出現(xiàn)一個(gè)實(shí)例時(shí),單例對(duì)...
摘要:使用元類可以控制類的創(chuàng)建過(guò)程,它主要做三件事攔截類的創(chuàng)建修改類的定義返回修改后的類使用元類實(shí)現(xiàn)單例模式的代碼如下執(zhí)行結(jié)果 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設(shè)計(jì)模式,該模式的主要目的是確保某一個(gè)類只有一個(gè)實(shí)例存在。當(dāng)你希望在整個(gè)系統(tǒng)中,某個(gè)類只能出現(xiàn)一個(gè)實(shí)例時(shí),單例對(duì)象就能派上用場(chǎng)。 比如,某個(gè)服務(wù)器程序的配置信息存放在一個(gè)文件中,客戶端通過(guò)一個(gè) ...
摘要:實(shí)現(xiàn)實(shí)現(xiàn)單例模式有多種方案使用提供了非常易用的類,只要繼承它,就會(huì)成為單例。參考鏈接單例模式最后,感謝女朋友支持。 問(wèn)題:現(xiàn)代化的巧克力工廠具備計(jì)算機(jī)控制的巧克力鍋爐。鍋爐做的事情就是把巧克力和牛奶融在一起,然后送到下一個(gè)階段,以制成巧克力棒。下邊是一個(gè)巧克力公司鍋爐控制器的代碼,仔細(xì)觀察一下,這段代碼有什么問(wèn)題? class ChocolateBoiler(object): ...
摘要:最近在學(xué)習(xí)設(shè)計(jì)模式而開發(fā)的語(yǔ)言中比較中意的就是了在這里總結(jié)下設(shè)計(jì)模式一般分為三大類構(gòu)造型結(jié)構(gòu)型行為型先從創(chuàng)建型設(shè)計(jì)模式開始創(chuàng)建型設(shè)計(jì)模式包括單例模式抽象工廠模式工廠方法模式生成器模式惰性初始化模式對(duì)象池模式原型模式單例模式單例模式的定義是保 最近在學(xué)習(xí)設(shè)計(jì)模式,而開發(fā)的語(yǔ)言中比較中意的就是python了,在這里總結(jié)下. 設(shè)計(jì)模式一般分為三大類:構(gòu)造型,結(jié)構(gòu)型,行為型 先從創(chuàng)建型設(shè)計(jì)模式...
閱讀 1875·2021-09-27 13:35
閱讀 3429·2019-08-30 14:16
閱讀 2483·2019-08-30 10:52
閱讀 859·2019-08-29 16:35
閱讀 1416·2019-08-29 15:22
閱讀 3641·2019-08-23 18:21
閱讀 3133·2019-08-23 18:00
閱讀 3123·2019-08-23 16:50