標籤:不能 使用 pass func 是你 main 刪除 class pyc
@(python之路)[物件導向, 單例模式]
[TOC]
單利模式
單例模式:是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個執行個體存在。當你希望在整個系統中,某個類只能出現一個執行個體時,單例對象就能派上用場。
單例模式的特點:
- 一、某個類只能有一個執行個體;
- 二、他必須自行建立這個執行個體;
- 三、它必須自行想整個系統提供這個執行個體;
實現單利模式的方法
- 使用模組
- 使用__new__
- 使用裝飾器(decorator)
- 使用元類(metaclass)
使用模組
在模組第一次匯入時,會產生.pyc檔案,當第二次匯入時,就會一直載入.pyc檔案,而不會再一次執行本次代碼。因此,我們只獲得了一個單例模式。
例如:
#mysingleton.pyclass MySingleton(object): def foo(self): print("My singleton")mysingleton = MySingleton()
#main.pyfrom mysingleton import mysingletonmysingleton.foo()
使用__new__
為了使類只能出現一個執行個體,我們可以使用 new 來控制執行個體的建立過程,代碼如下:
class Singleton(object): _instance = None def __new__(cls, *args, **kw): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kw) #這裡的super的意思是,該怎麼走就怎麼走。 return cls._instance class MyClass(Singleton): a = 1
在上面的代碼中,我們將類的執行個體和一個類變數 _instance 關聯起來,如果 cls._instance 為 None 則建立執行個體,否則直接返回 cls._instance。
執行情況:
>>> one = MyClass()>>> two = MyClass()>>> one == twoTrue>>> one is twoTrue>>> id(one), id(two)(4303862668, 4303862668)
使用裝飾器
我們知道,裝飾器(decorator)可以動態地修改一個類或函數的功能。這裡,我們也可以使用裝飾器來裝飾某個類,使其只能產生一個執行個體,代碼如下:
from functools import wraps def singleton(cls): instances = {} @wraps(cls) def getinstance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return getinstance@singletonclass MyClass(object): a = 1
在上面,我們定義了一個裝飾器 singleton,它返回了一個內建函式 getinstance,該函數會判斷某個類是否在字典 instances 中,如果不存在,則會將 cls 作為 key,cls(*args, **kw) 作為 value 存到 instances 中,否則,直接返回 instances[cls]。
使用 metaclass
元類(metaclass)可以控制類的建立過程,它主要做三件事:
用元類實現單例模式的代碼:
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] # Python2# class MyClass(object):# __metaclass__ = Singleton # Python3class MyClass(metaclass=Singleton): pass
優點
- 一、執行個體控制
單例模式會組織其他對象執行個體化自己的單例對象的副本,從而確保對所有對象都訪問唯一執行個體。
- 二、靈活性
因為類控制了執行個體化過程,所以類可以靈活更改執行個體化過程。
缺點
- 一、開銷
雖然開銷數量小,但是如果每次對對象請求都要檢查是否存在類的執行個體,仍然需要一些開銷。可以通過使用靜態初始化解決此問題。
- 二、可能的開發混淆
使用單例對象(尤其是在類庫中定義的對象)時,開發人員必須記住不能使用new關鍵字執行個體化對象。因為可能無法訪問庫原始碼,因此應用程式開發人員可能會意外發現自己五發直接執行個體化此類。
- 三、對象生存周期
不能解決刪除對象的問題。在提供記憶體管理的語言中(例如基於.NET Framework的語言),只有單例類能夠導致執行個體被取消分配,因為它包含該執行個體的私人化引用。在某些語言中(如C++),其他類可以刪除對象執行個體,但這樣會導致執行個體類中出現懸浮引用。
補充:元類(metaclass)
注釋:
?類也是對象;只要你使用關鍵字class,python解譯器在執行的時候就好會建立一個對象。
例如:
class Foo(object): pass
這段代碼將在記憶體中建立於一個對象,名字為Foo。這個對象(類)自身擁有建立類對象(類實力)的能力,而這就是為什麼他是一個類的原因。但是,他本質仍然時一個對象,於是乎你可以對它的操作如下
- 將它複製給一個變數
- 拷貝
- 增加它的屬性
- 將他作為函數進行傳遞
>>> class Foo(object):... pass...>>> print(Foo) # 列印一個類,因為他是一個對象<class '__main__.Foo'>##########################################>>> def echo(o):... print(o)...>>> echo(Foo) # 將類當作參數傳給函數<class '__main__.Foo'>#########################################>>> Foo.new_attribute = "foo" # 增加類的屬性>>> print(hasattr(Foo,"new_attribute"))True>>> print(Foo.new_attribute)foo##########################################MyFoo = Fooprint(MyFoo()) # 可以將類賦值給一個變數
動態地建立類
因為類也是對象,可以在運行時動態建立他們,就像其他任何對象一樣。首先,你可以在函數中建立類,使用class關鍵字即可。
def choose_class(name): if name == 'foo': class Foo(object): pass return Foo # 返回的是類,不是類的執行個體 else: class Bar(object): pass return Bar MyClass = choose_class('foo')print(MyClass) # 函數返回的是類,不是類的執行個體# <class '__main__.choose_class.<locals>.Foo'> print(MyClass()) # 你可以通過這個類建立類執行個體,也就是對象# <__main__.choose_class.<locals>.Foo object at 0x00000000021E5CF8>
type動態建立類。
type可以這樣工作
type(類名, 父類的元組(針對繼承的情況,可以為空白),包含屬性的字典(名稱和值))
例如下面的代碼:
class MyTypeClass(object): pass
可以用type的方式去建立:
>>> MyTypeClass = type("MyTypeClass",(),{}) # 返回一個對象>>> print(MyTypeClass)<class '__main__.MyTypeClass'>>>> print(MyTypeClass()) # 建立一個類的執行個體<__main__.MyTypeClass object at 0x0542A590>
type接收一個字典來為類定義屬性,因此:
class Foo(object): bar = True
可以翻譯為:
Foo = type("Foo",(),{"bar":True})
也可以將Foo當成一個普通類使用:
class Foo(object): bar = True>>> print(Foo)<class '__main__.Foo'>>>> print(Foo.bar)True>>>
也可以繼承
class FooTwo(Foo): pass
也可以寫成:
class Foo(object): bar = TrueFooTwo = type("FooTwo",(Foo,),{})>>> print(FooTwo)<class '__main__.FooTwo'>>>> print(FooTwo.bar) # bar屬性由Foo繼承而來True
在python中,類也是對象,你可以動態建立類。這就是你使用關鍵字class時python在幕後做的事情,而這就通過元類實現的。
什麼時元類,元類就是用來建立類的東西。元類就是類的類。
函數type實際上時一個元類。type就是python在背後用來建立所有類的元類。
type就是建立類對象的類,可以用__class__屬性來看到這一點。
python中所有的東西,注意這裡的東西都是對象。包括整數,字串,函數以及類,他們全都是對象,而且他們都是一個類建立而來。
age = 35print(age.__class__) #<class 'int'> name = 'bob'print(name.__class__) #<class 'str'> def foo(): passprint(foo.__class__) #<class 'function'> class Bar(object): passb = Bar()print(b.__class__) #<class '__main__.Bar'>
現在,對於任何一個__class__的__class__屬性又是什麼呢。
print(age.__class__.__class__) #<class 'type'>print(name.__class__.__class__) #<class 'type'>print(foo.__class__.__class__) #<class 'type'>print(b.__class__.__class__) #<class 'type'>
因此,元類就是建立類這種對象的東西。
type就是python得內建元類,當然你可以建立自己的元類。
__metaclass__屬性
你可以在寫一個類得時候為其添加__metaclass__屬性。
class Foo(object): __metaclass__ = something...
Python會在類的定義中尋找__metaclass__屬性,如果找到了,Python就會用它來建立類Foo,如果沒有找到,就會用內建的type來建立這個類。
註:本片部落格借鑒網友一片部落格,地址找不到了。
python物件導向, 單例模式