国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

詳解python單例模式與metaclass

2019-11-25 16:59:09
字體:
供稿:網(wǎng)友

單例模式的實(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@singletonclass MyClass(object):  pass

問題是這樣裝飾以后返回的不是類而是函數(shù),當(dāng)然你可以singleton里定義一個(gè)類來解決問題,但這樣就顯得很麻煩了

使用__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__ = Singleton

metaclass

元類就是用來創(chuàng)建類的東西,可以簡單把元類稱為“類工廠”,類是元類的實(shí)例。type就是Python的內(nèi)建元類,type也是自己的元類,任何一個(gè)類

>>> type(MyClass)type>>> type(type)type

python在創(chuàng)建類MyClass的過程中,會(huì)在類的定義中尋找__metaclass__,如果存在則用其創(chuàng)建類MyClass,否則使用內(nèi)建的type來創(chuàng)建類。對于類有繼承的情況,如果當(dāng)前類沒有找到,會(huì)繼續(xù)在父類中尋找__metaclass__,直到所有父類中都沒有找到才使用type創(chuàng)建類。
如果模塊里有__metaclass__的全局變量的話,其中的類都將以其為元類,親自試了,沒這個(gè)作用,無任何影響

查看type的定義,

type(object) -> the object's type
type(name, bases, dict) -> a new type

所以利用type定義一個(gè)類的元類,可以用函數(shù)返回一個(gè)上面第二種定義的對象,也可以繼承type并重寫其中的方法。

直接使用type生成的對象作為元類,函數(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 = 2d = Singleton()print d.ABC# 2

上一節(jié)中,單例模式元類實(shí)現(xiàn)用的是類繼承方式,而對于第一種__new__的方式,本質(zhì)上調(diào)用的是type.__new__,不過使用super能使繼承更清晰一些并避免一些問題

這里簡單說明一下,__new__是在__init__前調(diào)用的方法,會(huì)創(chuàng)建對象并返回,而__init__則是用傳入的參數(shù)將對象初始化。看一下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 """  passdef __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中任何一種都是可以的,來看一下使用元類時(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: <class '__main__.Basic'> 'Foo' () {'__module__': '__main__', '__metaclass__': <class '__main__.Basic'>, '__init__': <function init at 0x106fd5320>}init: <class '__main__.Foo'> 'Foo' () {'__module__': '__main__', '__metaclass__': <class '__main__.Basic'>, '__init__': <function init at 0x106fd5320>}call: <class '__main__.Foo'> ('a',)init: <__main__.Foo object at 0x106fee990> ('a',) {}call: <class '__main__.Foo'> ('b',)init: <__main__.Foo object at 0x106feea50> ('b',) {}

元類的__init__和__new__只在創(chuàng)建類Foo調(diào)用了一次,而創(chuàng)建Foo的實(shí)例時(shí),每次都會(huì)調(diào)用元類的__call__方法

以上就是本文的全部內(nèi)容,對python單例模式與metaclass進(jìn)行了描述,希望對大家的學(xué)習(xí)有所幫助。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 上林县| 四川省| 辽宁省| 当涂县| 清徐县| 叶城县| 临武县| 平定县| 佛学| 乌拉特后旗| 荔波县| 闸北区| 利辛县| 句容市| 万载县| 岢岚县| 宜良县| 江西省| 临夏市| 梧州市| 青田县| 怀集县| 历史| 东丰县| 宣汉县| 阿勒泰市| 玉林市| 凭祥市| 察雅县| 新竹县| 略阳县| 周至县| 宝丰县| 德庆县| 新沂市| 芦山县| 涟源市| 四川省| 茂名市| 平邑县| 濮阳市|