Python中的魔法属性
魔法屬性
在Python中,所有以 __ 雙下劃線包起來的方法,都統(tǒng)稱為 Magic Method,例如類的初始化方法 __init__() ,實(shí)例對(duì)象創(chuàng)造方法 __new__()等。
魔法屬性和方法是Python內(nèi)置的一些屬性和方法,有著特殊的含義。命名時(shí)前后加上兩個(gè)下劃線,在執(zhí)行系統(tǒng)特定操作時(shí),會(huì)自動(dòng)調(diào)用。
常見的魔法屬性
__doc__
表示類的描述信息
#?__doc__ class?Foo:"""?描述類信息,這是用于測(cè)試的類?"""def?func(self):pass#?ipython?測(cè)驗(yàn) In?[2]:?Foo.__doc__ Out[2]:?'?描述類信息,這是用于測(cè)試的類?'__module__ 和 ?__class__
__module__ 表示當(dāng)前操作的對(duì)象在那個(gè)模塊
__class__ 表示當(dāng)前操作的對(duì)象的類是什么
__init__ 、__new__
__init__() 初始化方法 和 __new__(),通過類創(chuàng)建對(duì)象時(shí),自動(dòng)觸發(fā)執(zhí)行。__new__ 是用來創(chuàng)建類并返回這個(gè)類的實(shí)例,而 __init__ 只是將傳入的參數(shù)來初始化該實(shí)例。
__new__() 創(chuàng)建對(duì)象時(shí)調(diào)用,會(huì)返回當(dāng)前對(duì)象的一個(gè)實(shí)例
__init__() 創(chuàng)建完對(duì)象后調(diào)用,對(duì)當(dāng)前對(duì)象的一些實(shí)例初始化,無返回值
__del__
當(dāng)對(duì)象在內(nèi)存中被釋放時(shí),自動(dòng)觸發(fā)執(zhí)行。
注:此方法一般無須定義,因?yàn)镻ython是一門高級(jí)語言,有 內(nèi)存管理、垃圾回收機(jī)制,程序員在使用時(shí)無需關(guān)心內(nèi)存的分配和釋放,因?yàn)榇斯ぷ鞫际墙唤oPython解釋器來執(zhí)行,所以,__del__ 的調(diào)用是由解釋器在進(jìn)行垃圾回收時(shí)自動(dòng)觸發(fā)執(zhí)行的。
#?__del__ class?Foo:def?__del__(self):print('__del__()?called')#?ipython?測(cè)驗(yàn) In?[29]:?f?=?Foo()In?[30]:?del?f __del__()?called__call__
讓類的實(shí)例的行為表現(xiàn)的像函數(shù)一樣,你可以調(diào)用它們,將一個(gè)函數(shù)當(dāng)做一個(gè)參數(shù)傳到另外一個(gè)函數(shù)中等等。這是一個(gè)非常強(qiáng)大的特性,其讓Python編程更加舒適甜美。對(duì)象后面加括號(hào),觸發(fā)執(zhí)行。
注:__init__ 方法的執(zhí)行是由創(chuàng)建對(duì)象觸發(fā)的,即:對(duì)象 = 類名() ;而對(duì)于 __call__ 方法的執(zhí)行是由對(duì)象后加括號(hào)觸發(fā)的,即:對(duì)象() 或者 類()()
__call__ 在那些 類的實(shí)例經(jīng)常改變狀態(tài)的時(shí)候會(huì)非常有效。調(diào)用這個(gè)實(shí)例是一種改變這個(gè)對(duì)象狀態(tài)的直接和優(yōu)雅的做法。用一個(gè)實(shí)例來表達(dá)最好不過了:
#?__call__ class?Rect(object)"""調(diào)用實(shí)例對(duì)象來改變矩形的位置"""def?__init__(self,?x,?y):#?x,?y代表矩形坐標(biāo)self.x,?self.y?=?x,?ydef?__call__(self,?x,?y):????????#?改變實(shí)體的位置self.x,?self.y?=?x,?y#?ipython?測(cè)驗(yàn) In?[33]:?r?=?Rect(10,?10)In?[34]:?r.x,?r.y Out[34]:?(10,?10)In?[35]:?r(0,?0)In?[36]:?r.x,?r.y Out[36]:?(0,?0)In?[37]:?r(100,?100)In?[38]:?r.x,?r.y Out[38]:?(100,?100)__dict__
類或?qū)ο笾械乃袑傩?/p>
類的實(shí)例屬性屬于對(duì)象;類中的類屬性和方法等屬于類,即:
#?__dict__ class?Student(object):def?__init__(self,?name,?age):self.name?=?nameself._age?=?age@propertydef?age(self):return?self._age#?ipython?測(cè)驗(yàn) In?[47]:?#?獲取類屬性In?[48]:?Student.__dict__ Out[48]: mappingproxy({'__module__':?'__main__','__init__':?<function?__main__.Student.__init__(self,?name,?age)>,'age':?<property?at?0x210e2a005e8>,'__dict__':?<attribute?'__dict__'?of?'Student'?objects>,'__weakref__':?<attribute?'__weakref__'?of?'Student'?objects>,'__doc__':?None})In?[49]:?#?獲取實(shí)例對(duì)象的屬性In?[50]:?s?=?Student('hui',?21)In?[51]:?s.__dict__ Out[51]:?{'name':?'hui',?'_age':?21}In?[52]:?s2?=?Student('jack',?20)In?[53]:?s2.__dict__ Out[53]:?{'name':?'jack',?'_age':?20}__str__
如果一個(gè)類中定義了__str__方法,那么在打印 對(duì)象 時(shí),默認(rèn)輸出該方法的返回值。
In?[65]:?#?__str__...:?class?Foo(object):...:?????pass...:In?[66]:?f?=?Foo()In?[67]:?print(f) <__main__.Foo?object?at?0x00000210E2715608>In?[68]:?class?Foo(object):...:...:?????def?__str__(self):...:?????????return?'<?Custom?Foo?object?str?>'...:In?[69]:?f?=?Foo()In?[70]:?print(f) <?Custom?Foo?object?str?>__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分別表示獲取、設(shè)置、刪除數(shù)據(jù)。
用于切片操作,如列表。
字典示例
#?__getitem__、__setitem__、__delitem__ class?MyDict(object):def?__init__(self):self.my_dict?=?dict()def?__getitem__(self,?key):print('__getitem__()?',?key)return?self.my_dict.get(key,?None)def?__setitem__(self,?key,?value):print('__setitem__()?',?key,?value)self.my_dict.update(key=value)def?__delitem__(self,?key):print('__delitem__()?',?key)del?self.my_dict[key]#?ipython?測(cè)驗(yàn)???????? In?[33]:?mdict?=?MyDict()In?[34]:?print(mdict['name']) __getitem__()??name NoneIn?[35]:?#?新增In?[36]:?mdict['name']?=?'hui' __setitem__()??name?huiIn?[37]:?mdict['age']?=?21 __setitem__()??age?21In?[38]:?mdict['name'] __getitem__()??name Out[38]:?'hui'In?[39]:?mdict['age'] __getitem__()??age Out[39]:?21In?[40]:?#?更新In?[41]:?mdict['name']?=?'jack' __setitem__()??name?jackIn?[42]:?mdict['name'] __getitem__()??name Out[42]:?'jack'In?[43]:?#?刪除In?[44]:?del?mdict['age'] __delitem__()??ageIn?[45]:?print(mdict['age']) __getitem__()??age None列表示例
#?切片操作 class?MyList(object):def?__init__(self):self.mlist?=?list()def?__getitem__(self,?index):print('__getitem__()?called')print(index)if?isinstance(index,?slice):return?self.mlist[index]def?__setitem__(self,?index,?value):print('__getitem__()?called')print(index,?value)if?isinstance(index,?slice):self.mlist[index]?=?valuedef?__delitem__(self,?index):print('__delitem__()?called')if?isinstance(index,?slice):del?self.mlist[index]#?ipython?測(cè)驗(yàn) In?[70]:?mlist?=?MyList()In?[71]:?mlist[0] __getitem__()?called 0In?[72]:?mlist[0:-1] __getitem__()?called slice(0,?-1,?None) Out[72]:?[]In?[73]:?mlist[:]?=?[1,2,3] __getitem__()?called slice(None,?None,?None)?[1,?2,?3]In?[74]:?mlist[:] __getitem__()?called slice(None,?None,?None) Out[74]:?[1,?2,?3]In?[75]:?mlist[0:2] __getitem__()?called slice(0,?2,?None) Out[75]:?[1,?2]In?[76]:?mlist[::-1] __getitem__()?called slice(None,?None,?-1) Out[76]:?[3,?2,?1]In?[77]:?mlist[0] __getitem__()?called 0In?[78]:?mlist[0:1] __getitem__()?called slice(0,?1,?None) Out[78]:?[1]In?[79]:?del?mlist[0:1] __delitem__()?calledIn?[80]:?mlist[:] __getitem__()?called slice(None,?None,?None) Out[80]:?[2,?3]注意: 當(dāng)進(jìn)行 mlist[0] 操作的時(shí)候傳遞并不是一個(gè) slice 對(duì)象,不是一個(gè) int 類型的數(shù)字,所以不能把索引為 0 的值取出來,改成 mlist[0, 1] 或者在 __getitem__() 的方法中新增數(shù)字判斷,大家可以嘗試一下。
__enter__、__exit__
with 聲明是從 Python2.5 開始引進(jìn)的關(guān)鍵詞。你應(yīng)該遇過這樣子的代碼:
with?open('foo.txt')?as?bar:#?do?something?with?barpass在 with 聲明的代碼段中,我們可以做一些對(duì)象的開始操作和退出操作,還能對(duì)異常進(jìn)行處理。這需要實(shí)現(xiàn)兩個(gè)魔術(shù)方法: __enter__ 和 __exit__。
__enter__(self):定義了當(dāng)使用 with 語句的時(shí)候,會(huì)話管理器在塊被初始創(chuàng)建時(shí)要產(chǎn)生的行為。請(qǐng)注意,__enter__ 的返回值與 with 語句的目標(biāo)或者 as 后的名字綁定。
__exit__(self,?exception_type,?exception_value,?traceback):定義了當(dāng)一個(gè)代碼塊被執(zhí)行或者終止后,會(huì)話管理器應(yīng)該做什么。它可以被用來處理異常、執(zhí)行清理工作或做一些代碼塊執(zhí)行完畢之后的日常工作。如果代碼塊執(zhí)行成功,exception_type,exception_value,和traceback 將會(huì)為 None 。否則,你可以選擇處理這個(gè)異常或者是直接交給用戶處理。如果你想處理這個(gè)異常的話,請(qǐng)確保__exit__ 在所有語句結(jié)束之后返回 True。如果你想讓異常被會(huì)話管理器處理的話,那么就讓其產(chǎn)生該異常。
__copy__、__deepcopy__
有時(shí)候,尤其是當(dāng)你在處理可變對(duì)象時(shí),你可能想要復(fù)制一個(gè)對(duì)象,然后對(duì)其做出一些改變而不希望影響原來的對(duì)象。這就是Python的copy所發(fā)揮作用的地方。
__copy__(self):定義了當(dāng)對(duì)你的類的實(shí)例調(diào)用 copy.copy() 時(shí)所產(chǎn)生的行為。copy.copy() 返回了你的對(duì)象的一個(gè)淺拷貝——這意味著,當(dāng)實(shí)例本身是一個(gè)新實(shí)例時(shí),它的所有數(shù)據(jù)都被引用了——例如,當(dāng)一個(gè)對(duì)象本身被復(fù)制了,它的數(shù)據(jù)仍然是被引用的(因此,對(duì)于淺拷貝中數(shù)據(jù)的更改仍然可能導(dǎo)致數(shù)據(jù)在原始對(duì)象的中的改變)。
__deepcopy__(self,?memodict={}):定義了當(dāng)對(duì)你的類的實(shí)例調(diào)用 copy.deepcopy()時(shí)所產(chǎn)生的行為。copy.deepcopy() 返回了你的對(duì)象的一個(gè)深拷貝——對(duì)象和其數(shù)據(jù)都被拷貝了。memodict 是對(duì)之前被拷貝的對(duì)象的一個(gè)緩存——這優(yōu)化了拷貝過程并且阻止了對(duì)遞歸數(shù)據(jù)結(jié)構(gòu)拷貝時(shí)的無限遞歸。當(dāng)你想要進(jìn)行對(duì)一個(gè)單獨(dú)的屬性進(jìn)行深拷貝時(shí),調(diào)用copy.deepcopy(),并以 memodict 為第一個(gè)參數(shù)。
這些魔術(shù)方法的用例看起來很小,并且確實(shí)非常實(shí)用. 它們反應(yīng)了關(guān)于面向?qū)ο蟪绦蛏弦恍┲匾臇|西在Python 上,并且總的來說 Python 總是一個(gè)簡(jiǎn)單的方法去找某些事情,即使是沒有必要的。這些魔法方法可能看起來不是很有用,但是一旦你需要它們,你會(huì)感到慶幸它們的存在。
其他魔法方法
由于魔法屬性、方法太多了在這就不一一描述和展示了,其他的就以表格形式呈現(xiàn)吧。
用于比較的魔術(shù)方法
| __cmp__(self, other) | 比較方法里面最基本的的魔法方法 |
| __eq__(self, other) | 定義相等符號(hào)的行為,== |
| __ne__(self,other) | 定義不等符號(hào)的行為,!= |
| __lt__(self,other) | 定義小于符號(hào)的行為,< |
| __gt__(self,other) | 定義大于符號(hào)的行為,> |
| __le__(self,other) | 定義小于等于符號(hào)的行為,<= |
| __ge__(self,other) | 定義大于等于符號(hào)的行為,>= |
數(shù)值計(jì)算的魔術(shù)方法
單目運(yùn)算符和函數(shù)
| __pos__(self) | 實(shí)現(xiàn)一個(gè)取正數(shù)的操作 |
| __neg__(self) | 實(shí)現(xiàn)一個(gè)取負(fù)數(shù)的操作 |
| __abs__(self) | 實(shí)現(xiàn)一個(gè)內(nèi)建的 abs() 函數(shù)的行為 |
| __invert__(self) | 實(shí)現(xiàn)一個(gè)取反操作符(~操作符)的行為 |
| __round__(self, n) | 實(shí)現(xiàn)一個(gè)內(nèi)建的 round() 函數(shù)的行為 |
| __floor__(self) | 實(shí)現(xiàn) math.floor() 的函數(shù)行為 |
| __ceil__(self) | 實(shí)現(xiàn) math.ceil() 的函數(shù)行為 |
| __trunc__(self) | 實(shí)現(xiàn) math.trunc() 的函數(shù)行為 |
雙目運(yùn)算符或函數(shù)
| __add__(self, other) | 實(shí)現(xiàn)一個(gè)加法 |
| __sub__(self, other) | 實(shí)現(xiàn)一個(gè)減法 |
| __mul__(self, other) | 實(shí)現(xiàn)一個(gè)乘法 |
| __floordiv__(self, other) | 實(shí)現(xiàn)一個(gè) // 操作符產(chǎn)生的整除操作 |
| __div__(self, other) | 實(shí)現(xiàn)一個(gè) / 操作符代表的除法操作 |
| __truediv__(self, other) | 實(shí)現(xiàn)真實(shí)除法 |
| __mod__(self, other) | 實(shí)現(xiàn)一個(gè) % 操作符代表的取模操作 |
| __divmod__(self, other) | 實(shí)現(xiàn)一個(gè)內(nèi)建函數(shù) divmod() |
| __pow__(self, other) | 實(shí)現(xiàn)一個(gè)指數(shù)操作( ****** 操作符)的行為 |
| __lshift__(self, other) | 實(shí)現(xiàn)一個(gè)位左移操作**(<<)**的功能 |
| __rshift__(self, other) | 實(shí)現(xiàn)一個(gè)位右移操作**(>>)**的功能 |
| __and__(self, other) | 實(shí)現(xiàn)一個(gè)按位進(jìn)行與操作**(&)**的行為 |
| __or__(self, other) | 實(shí)現(xiàn)一個(gè)按位進(jìn)行或操作的行為 |
| __xor__(self, other) | 異或運(yùn)算符相當(dāng)于 ^ |
增量運(yùn)算
| __iadd__(self, other) | 加法賦值 |
| __isub__(self, other) | 減法賦值 |
| __imul__(self, other) | 乘法賦值 |
| __ifloordiv__(self, other) | 整除賦值,地板除,相當(dāng)于 //= 運(yùn)算符 |
| __idiv__(self, other) | 除法賦值,相當(dāng)于 /= 運(yùn)算符 |
| __itruediv__(self, other) | 真除賦值 |
| __imod_(self, other) | 模賦值,相當(dāng)于 %= 運(yùn)算符 |
| __ipow__(self, other) | 乘方賦值,相當(dāng)于 ?**= ?運(yùn)算符 |
| __ilshift__(self, other) | 左移賦值,相當(dāng)于 <<= 運(yùn)算符 |
| __irshift__(self, other) | 左移賦值,相當(dāng)于 >>= 運(yùn)算符 |
| __iand__(self, other) | 與賦值,相當(dāng)于 &= 運(yùn)算符 |
| __ior__(self, other) | 或賦值 |
| __ixor__(self, other) | 異或運(yùn)算符,相當(dāng)于 ^= 運(yùn)算符 |
類型轉(zhuǎn)換
| __int__(self) | 轉(zhuǎn)換成整型 |
| __long__(self) | 轉(zhuǎn)換成長(zhǎng)整型 |
| __float__(self) | 轉(zhuǎn)換成浮點(diǎn)型 |
| __complex__(self) | 轉(zhuǎn)換成 復(fù)數(shù)型 |
| __oct__(self) | 轉(zhuǎn)換成八進(jìn)制 |
| __hex__(self) | 轉(zhuǎn)換成十六進(jìn)制 |
| __index__(self) | 如果你定義了一個(gè)可能被用來做切片操作的數(shù)值型,你就應(yīng)該定義__index__ |
| __trunc__(self) | 當(dāng) math.trunc(self) ?使用時(shí)被調(diào)用 __trunc__ 返回自身類型的整型截取 |
| __coerce__(self, other) | 執(zhí)行混合類型的運(yùn)算 |
大自然用數(shù)百億年創(chuàng)造出我們現(xiàn)實(shí)世界,而程序員用幾百年創(chuàng)造出一個(gè)完全不同的虛擬世界。我們用鍵盤敲出一磚一瓦,用大腦構(gòu)建一切。人們把1000視為權(quán)威,我們反其道行之,捍衛(wèi)1024的地位。我們不是鍵盤俠,我們只是平凡世界中不凡的締造者 。
推薦閱讀
誤執(zhí)行了rm -fr /*之后,除了跑路還能怎么辦?!
程序員必備58個(gè)網(wǎng)站匯總
大幅提高生產(chǎn)力:你需要了解的十大Jupyter Lab插件
總結(jié)
以上是生活随笔為你收集整理的Python中的魔法属性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一次打包,无限复用!教你用 PyChar
- 下一篇: 轻松解决Python “字符编码”,玩儿