單例模式的實現方式
將類實例綁定到類變量上
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@singletonclass 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__ = Singleton
metaclass
元類就是用來創建類的東西,可以簡單把元類稱為“類工廠”,類是元類的實例。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 = 2d = Singleton()print d.ABC# 2
上一節中,單例模式元類實現用的是類繼承方式,而對于第一種__new__的方式,本質上調用的是type.__new__,不過使用super能使繼承更清晰一些并避免一些問題
這里簡單說明一下,__new__是在__init__前調用的方法,會創建對象并返回,而__init__則是用傳入的參數將對象初始化??匆幌聇ype中這兩者以及__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 """ passdef __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: <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__只在創建類Foo調用了一次,而創建Foo的實例時,每次都會調用元類的__call__方法
以上就是本文的全部內容,對python單例模式與metaclass進行了描述,希望對大家的學習有所幫助。