详解python单例模式与metaclass
单例模式的实现方式
将类实例绑定到类变量上
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__ = 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 = 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: <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进行了描述,希望对大家的学习有所帮助。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。
