本文目錄一覽:
- 1、詳解Python中的__new__、__init__、__call__三個特殊方法
- 2、Python中常見魔法方法介紹
- 3、python中什麼是特殊方法
- 4、python元編程中一些處理屬性的特殊方法
詳解Python中的__new__、__init__、__call__三個特殊方法
__new__: 對象的創建,是一個靜態方法,第一個參數是cls。(想想也是,不可能是self,對象還沒創建,哪來的self)
__init__ : 對象的初始化, 是一個實例方法,第一個參數是self。
__call__ : 對象可call,注意不是類,是對象。
先有創建,才有初始化。即先__new__,而後__init__。
上面說的不好理解,看例子。
1.對於__new__
可以看到,輸出來是一個Bar對象。
__new__方法在類定義中不是必須寫的,如果沒定義,默認會調用object.__new__去創建一個對象。如果定義了,就是override,可以custom創建對象的行為。
聰明的讀者可能想到,既然__new__可以custom對象的創建,那我在這裡做一下手腳,每次創建對象都返回同一個,那不就是單例模式了嗎?沒錯,就是這樣。可以觀摩《飄逸的python – 單例模式亂彈》
定義單例模式時,因為自定義的__new__重載了父類的__new__,所以要自己顯式調用父類的__new__,即object.__new__(cls, *args, **kwargs),或者用super()。,不然就不是extend原來的實例了,而是替換原來的實例。
2.對於__init__
使用Python寫過面向對象的代碼的同學,可能對 __init__ 方法已經非常熟悉了,__init__ 方法通常用在初始化一個類實例的時候。例如:
這樣便是__init__最普通的用法了。但__init__其實不是實例化一個類的時候第一個被調用 的方法。當使用 Persion(name, age) 這樣的表達式來實例化一個類時,最先被調用的方法 其實是 __new__ 方法。
3.對於__call__
對象通過提供__call__(slef, [,*args [,**kwargs]])方法可以模擬函數的行為,如果一個對象x提供了該方法,就可以像函數一樣使用它,也就是說x(arg1, arg2…) 等同於調用x.__call__(self, arg1, arg2) 。模擬函數的對象可以用於創建防函數(functor) 或代理(proxy).
總結,在Python中,類的行為就是這樣,__new__、__init__、__call__等方法不是必須寫的,會默認調用,如果自己定義了,就是override,可以custom。既然override了,通常也會顯式調用進行補償以達到extend的目的。
這也是為什麼會出現”明明定義def _init__(self, *args, **kwargs),對象怎麼不進行初始化”這種看起來詭異的行為。(注,這裡_init__少寫了個下劃線,因為__init__不是必須寫的,所以這裡不會報錯,而是當做一個新的方法_init__)
Python中常見魔法方法介紹
魔法方法 (Magic Methods) 是Python中的內置函數,一般以雙下劃線開頭和結尾,例如__ init__ 、 __del__ 等。之所以稱之為魔法方法,是因為這些方法會在進行特定的操作時會自動被調用。
在Python中,可以通過dir()方法來查看某個對象的所有方法和屬性,其中雙下劃線開頭和結尾的就是該對象的魔法方法。以字元串對象為例:
可以看到字元串對象有 __add__ 方法,所以在Python中可以直接對字元串對象使用”+”操作,當Python識別到”+”操作時,就會調用該對象的 __add__ 方法。有需要時我們可以在自己的類中重寫 __add__ 方法來完成自己想要的效果。
我們重寫了 __add__ 方法,當Python識別”+”操作時,會自動調用重寫後的 __add__ 方法。可以看到,魔法方法在類或對象的某些事件出發後會自動執行,如果希望根據自己的程序定製特殊功能的類,那麼就需要對這些方法進行重寫。使用魔法方法,我們可以非常方便地給類添加特殊的功能。
1、構造與初始化
__ new __ 、 __ init __ 這兩個魔法方法常用於對類的初始化操作。上面我們創建a1 = A(“hello”)時,但首先調用的是 __ new __ ;初始化一個類分為兩步:
a.調用該類的new方法,返回該類的實例對象
b.調用該類的init方法,對實例對象進行初始化。
__new__ (cls, *args, **kwargs)至少需要一個cls參數,代表傳入的類。後面兩個參數傳遞給 __ init __ 。在 __ new __ 可以決定是否繼續調用 __ init __ 方法,只有當 __ new __ 返回了當前類cls的實例,才會接著調用 __ init __ 。結合 __ new __ 方法的特性,我們可以通過重寫 __ new __ 方法實現Python的單例模式:
可以看到雖然創建了兩個對象,但兩個對象的地址相同。
2、控制屬性訪問這類魔法
方法主要對對象的屬性進行訪問、定義、修改時起作用。主要有:
__getattr__(self, name): 定義當用戶試圖獲取一個屬性時的行為。
__getattribute__(self, name):定義當該類的屬性被訪問時的行為(先調用該方法,查看是否存在該屬性,若不存在,接著去調用getattr)。
__setattr__(self, name, value):定義當一個屬性被設置時的行為。
當初始化屬性時如self.a=a時或修改實例屬性如ins.a=1時本質時調用魔法方法self. __ setattr __ (name,values);當實例訪問某個屬性如ins.a本質是調用魔法方法a. __ getattr __ (name)
3、容器類操作
有一些方法可以讓我們自己定義自己的容器,就像Python內置的List,Tuple,Dict等等;容器分為可變容器和不可變容器。
如果自定義一個不可變容器的話,只能定義__ len__ 和__ getitem__ ;定義一個可變容器除了不可變容器的所有魔法方法,還需要定義__ setitem__ 和__ delitem__ ;如果容器可迭代。還需要定義__ iter __。
__len__(self):返回容器的長度
__getitem__(self,key):當需要執行self[key]的方式去調用容器中的對象,調用的是該方法
__setitem__(self,key,value):當需要執行self[key] = value時,調用的是該方法
__iter__(self):當容器可以執行 for x in container:,或者使用iter(container)時,需要定義該方法
下面舉一個例子,實現一個容器,該容器有List的一般功能,同時增加一些其它功能如訪問第一個元素,最後一個元素,記錄每個元素被訪問的次數等。
這類方法的使用場景主要在你需要定義一個滿足需求的容器類數據結構時會用到,比如可以嘗試自定義實現樹結構、鏈表等數據結構(在collections中均已有),或者項目中需要定製的一些容器類型。
魔法方法在Python代碼中能夠簡化代碼,提高代碼可讀性,在常見的Python第三方庫中可以看到很多對於魔法方法的運用。
因此當前這篇文章僅是拋磚引玉,真正的使用需要在開源的優秀源碼中以及自身的工程實踐中不斷加深理解併合適應用。
python中什麼是特殊方法
構造序列
1._len_(self)
2._getitem_(self,key)
3._setitem_(self,key,value)
4._delitem_(self,key)
程序演示:
myseq.py
class MySeq:
def __init__(self):
self.lseq = [“I”,”II”,”III”,”IV”]
def __len__(self):
return len(self.lseq)
def __getitem__(self,key):
if 0 = key 4:
return self.lseq[key]
if __name__ == ‘__main__’:
m = MySeq()
for i in range(4):
print(m[i])
python元編程中一些處理屬性的特殊方法
在用戶自己定義的類中,下述特殊方法用於獲取、設置、刪除和列出屬性
使用點號,或者內置的的getattr,hasattr, setattr函數存取屬性都會觸發下述列表中的特殊方法。但是,直接通過實例的 __dict__ 屬性來存取方法不會觸發這些特殊方法。所以,如果需要,在一些情況下,可以使用這種方法跳過特殊方法。
示例,假設有個名為 Class 的類,obj 是 Class 類的實例,attr 是 obj 的屬性。
obj.attr 和 getattr(obj, ‘attr’, 42)都會觸發 Class.__getattribute__(obj, ‘attr’) 方法。嘗試獲取指定屬性時總會調用這個方法,不過,尋找的屬性時特殊屬性或者特殊方法時除外。
del obj.attr 語句會觸發 Class.__delattr__(obj, ‘attr’) 方法。
dir(obj)語句會觸發 Class.__dir__(obj) 方法。
僅當獲取指定的屬性失敗,搜索過 obj、Class 和超類之後調用 Class.__getattr__(self, name)
嘗試設置指定的屬性時總會調用 Class.__setattr__(obj, ‘attr’, value) ,點號和setattr(obj, ‘attr’, 42)會調用這個方法。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/259765.html