Python中的魔法属性
魔法屬性
在Python中,所有以 __ 雙下劃線包起來的方法,都統稱為 Magic Method,例如類的初始化方法 __init__() ,實例對象創造方法 __new__()等。
魔法屬性和方法是Python內置的一些屬性和方法,有著特殊的含義。命名時前后加上兩個下劃線,在執行系統特定操作時,會自動調用。
常見的魔法屬性
__doc__
表示類的描述信息
#?__doc__ class?Foo:"""?描述類信息,這是用于測試的類?"""def?func(self):pass#?ipython?測驗 In?[2]:?Foo.__doc__ Out[2]:?'?描述類信息,這是用于測試的類?'__module__ 和 ?__class__
__module__ 表示當前操作的對象在那個模塊
__class__ 表示當前操作的對象的類是什么
__init__ 、__new__
__init__() 初始化方法 和 __new__(),通過類創建對象時,自動觸發執行。__new__ 是用來創建類并返回這個類的實例,而 __init__ 只是將傳入的參數來初始化該實例。
__new__() 創建對象時調用,會返回當前對象的一個實例
__init__() 創建完對象后調用,對當前對象的一些實例初始化,無返回值
__del__
當對象在內存中被釋放時,自動觸發執行。
注:此方法一般無須定義,因為Python是一門高級語言,有 內存管理、垃圾回收機制,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,__del__ 的調用是由解釋器在進行垃圾回收時自動觸發執行的。
#?__del__ class?Foo:def?__del__(self):print('__del__()?called')#?ipython?測驗 In?[29]:?f?=?Foo()In?[30]:?del?f __del__()?called__call__
讓類的實例的行為表現的像函數一樣,你可以調用它們,將一個函數當做一個參數傳到另外一個函數中等等。這是一個非常強大的特性,其讓Python編程更加舒適甜美。對象后面加括號,觸發執行。
注:__init__ 方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對于 __call__ 方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()
__call__ 在那些 類的實例經常改變狀態的時候會非常有效。調用這個實例是一種改變這個對象狀態的直接和優雅的做法。用一個實例來表達最好不過了:
#?__call__ class?Rect(object)"""調用實例對象來改變矩形的位置"""def?__init__(self,?x,?y):#?x,?y代表矩形坐標self.x,?self.y?=?x,?ydef?__call__(self,?x,?y):????????#?改變實體的位置self.x,?self.y?=?x,?y#?ipython?測驗 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__
類或對象中的所有屬性
類的實例屬性屬于對象;類中的類屬性和方法等屬于類,即:
#?__dict__ class?Student(object):def?__init__(self,?name,?age):self.name?=?nameself._age?=?age@propertydef?age(self):return?self._age#?ipython?測驗 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]:?#?獲取實例對象的屬性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__
如果一個類中定義了__str__方法,那么在打印 對象 時,默認輸出該方法的返回值。
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__
用于索引操作,如字典。以上分別表示獲取、設置、刪除數據。
用于切片操作,如列表。
字典示例
#?__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?測驗???????? 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?測驗 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]注意: 當進行 mlist[0] 操作的時候傳遞并不是一個 slice 對象,不是一個 int 類型的數字,所以不能把索引為 0 的值取出來,改成 mlist[0, 1] 或者在 __getitem__() 的方法中新增數字判斷,大家可以嘗試一下。
__enter__、__exit__
with 聲明是從 Python2.5 開始引進的關鍵詞。你應該遇過這樣子的代碼:
with?open('foo.txt')?as?bar:#?do?something?with?barpass在 with 聲明的代碼段中,我們可以做一些對象的開始操作和退出操作,還能對異常進行處理。這需要實現兩個魔術方法: __enter__ 和 __exit__。
__enter__(self):定義了當使用 with 語句的時候,會話管理器在塊被初始創建時要產生的行為。請注意,__enter__ 的返回值與 with 語句的目標或者 as 后的名字綁定。
__exit__(self,?exception_type,?exception_value,?traceback):定義了當一個代碼塊被執行或者終止后,會話管理器應該做什么。它可以被用來處理異常、執行清理工作或做一些代碼塊執行完畢之后的日常工作。如果代碼塊執行成功,exception_type,exception_value,和traceback 將會為 None 。否則,你可以選擇處理這個異常或者是直接交給用戶處理。如果你想處理這個異常的話,請確保__exit__ 在所有語句結束之后返回 True。如果你想讓異常被會話管理器處理的話,那么就讓其產生該異常。
__copy__、__deepcopy__
有時候,尤其是當你在處理可變對象時,你可能想要復制一個對象,然后對其做出一些改變而不希望影響原來的對象。這就是Python的copy所發揮作用的地方。
__copy__(self):定義了當對你的類的實例調用 copy.copy() 時所產生的行為。copy.copy() 返回了你的對象的一個淺拷貝——這意味著,當實例本身是一個新實例時,它的所有數據都被引用了——例如,當一個對象本身被復制了,它的數據仍然是被引用的(因此,對于淺拷貝中數據的更改仍然可能導致數據在原始對象的中的改變)。
__deepcopy__(self,?memodict={}):定義了當對你的類的實例調用 copy.deepcopy()時所產生的行為。copy.deepcopy() 返回了你的對象的一個深拷貝——對象和其數據都被拷貝了。memodict 是對之前被拷貝的對象的一個緩存——這優化了拷貝過程并且阻止了對遞歸數據結構拷貝時的無限遞歸。當你想要進行對一個單獨的屬性進行深拷貝時,調用copy.deepcopy(),并以 memodict 為第一個參數。
這些魔術方法的用例看起來很小,并且確實非常實用. 它們反應了關于面向對象程序上一些重要的東西在Python 上,并且總的來說 Python 總是一個簡單的方法去找某些事情,即使是沒有必要的。這些魔法方法可能看起來不是很有用,但是一旦你需要它們,你會感到慶幸它們的存在。
其他魔法方法
由于魔法屬性、方法太多了在這就不一一描述和展示了,其他的就以表格形式呈現吧。
用于比較的魔術方法
| __cmp__(self, other) | 比較方法里面最基本的的魔法方法 |
| __eq__(self, other) | 定義相等符號的行為,== |
| __ne__(self,other) | 定義不等符號的行為,!= |
| __lt__(self,other) | 定義小于符號的行為,< |
| __gt__(self,other) | 定義大于符號的行為,> |
| __le__(self,other) | 定義小于等于符號的行為,<= |
| __ge__(self,other) | 定義大于等于符號的行為,>= |
數值計算的魔術方法
單目運算符和函數
| __pos__(self) | 實現一個取正數的操作 |
| __neg__(self) | 實現一個取負數的操作 |
| __abs__(self) | 實現一個內建的 abs() 函數的行為 |
| __invert__(self) | 實現一個取反操作符(~操作符)的行為 |
| __round__(self, n) | 實現一個內建的 round() 函數的行為 |
| __floor__(self) | 實現 math.floor() 的函數行為 |
| __ceil__(self) | 實現 math.ceil() 的函數行為 |
| __trunc__(self) | 實現 math.trunc() 的函數行為 |
雙目運算符或函數
| __add__(self, other) | 實現一個加法 |
| __sub__(self, other) | 實現一個減法 |
| __mul__(self, other) | 實現一個乘法 |
| __floordiv__(self, other) | 實現一個 // 操作符產生的整除操作 |
| __div__(self, other) | 實現一個 / 操作符代表的除法操作 |
| __truediv__(self, other) | 實現真實除法 |
| __mod__(self, other) | 實現一個 % 操作符代表的取模操作 |
| __divmod__(self, other) | 實現一個內建函數 divmod() |
| __pow__(self, other) | 實現一個指數操作( ****** 操作符)的行為 |
| __lshift__(self, other) | 實現一個位左移操作**(<<)**的功能 |
| __rshift__(self, other) | 實現一個位右移操作**(>>)**的功能 |
| __and__(self, other) | 實現一個按位進行與操作**(&)**的行為 |
| __or__(self, other) | 實現一個按位進行或操作的行為 |
| __xor__(self, other) | 異或運算符相當于 ^ |
增量運算
| __iadd__(self, other) | 加法賦值 |
| __isub__(self, other) | 減法賦值 |
| __imul__(self, other) | 乘法賦值 |
| __ifloordiv__(self, other) | 整除賦值,地板除,相當于 //= 運算符 |
| __idiv__(self, other) | 除法賦值,相當于 /= 運算符 |
| __itruediv__(self, other) | 真除賦值 |
| __imod_(self, other) | 模賦值,相當于 %= 運算符 |
| __ipow__(self, other) | 乘方賦值,相當于 ?**= ?運算符 |
| __ilshift__(self, other) | 左移賦值,相當于 <<= 運算符 |
| __irshift__(self, other) | 左移賦值,相當于 >>= 運算符 |
| __iand__(self, other) | 與賦值,相當于 &= 運算符 |
| __ior__(self, other) | 或賦值 |
| __ixor__(self, other) | 異或運算符,相當于 ^= 運算符 |
類型轉換
| __int__(self) | 轉換成整型 |
| __long__(self) | 轉換成長整型 |
| __float__(self) | 轉換成浮點型 |
| __complex__(self) | 轉換成 復數型 |
| __oct__(self) | 轉換成八進制 |
| __hex__(self) | 轉換成十六進制 |
| __index__(self) | 如果你定義了一個可能被用來做切片操作的數值型,你就應該定義__index__ |
| __trunc__(self) | 當 math.trunc(self) ?使用時被調用 __trunc__ 返回自身類型的整型截取 |
| __coerce__(self, other) | 執行混合類型的運算 |
大自然用數百億年創造出我們現實世界,而程序員用幾百年創造出一個完全不同的虛擬世界。我們用鍵盤敲出一磚一瓦,用大腦構建一切。人們把1000視為權威,我們反其道行之,捍衛1024的地位。我們不是鍵盤俠,我們只是平凡世界中不凡的締造者 。
推薦閱讀
誤執行了rm -fr /*之后,除了跑路還能怎么辦?!
程序員必備58個網站匯總
大幅提高生產力:你需要了解的十大Jupyter Lab插件
總結
以上是生活随笔為你收集整理的Python中的魔法属性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一次打包,无限复用!教你用 PyChar
- 下一篇: 清华本硕男,月入5W征婚引群嘲“普通却自