python中那些雙下劃線開頭得函數和變量

python中那些雙下劃線開頭得函數和變量--轉載

Python中下劃線---完全解讀  

 

 

Python 用下劃線作爲變量前綴和後綴指定特殊變量

_xxx 不能用’from module import *’導入

__xxx__ 系統定義名字

__xxx 類中的私有變量名

核心風格避免用下劃線作爲變量名的開始。

 

因爲下劃線對解釋器有特殊的意義而且是內建標識符所使用的符號我們建議程序員避免用下劃線作爲變量名的開始。一般來講變量名_xxx被看作是“私有 的”在模塊或類外不可以使用。當變量是私有的時候用_xxx 來表示變量是很好的習慣。因爲變量名__xxx__對Python 來說有特殊含義對於普通的變量應當避免這種命名風格。

“單下劃線” 開始的成員變量叫做保護變量意思是隻有類對象和子類對象自己能訪問到這些變量
“雙下劃線” 開始的是私有成員意思是隻有類對象自己能訪問連子類對象也不能訪問到這個數據。

以單下劃線開頭_foo的代表不能直接訪問的類屬性需通過類提供的接口進行訪問不能用“from xxx import *”而導入以雙下劃線開頭的__foo代表類的私有成員以雙下劃線開頭和結尾的__foo__代表python裏特殊方法專用的標識如 __init__代表類的構造函數。

現在我們來總結下所有的系統定義屬性和方法 先來看下保留屬性

>>> Class1.__doc__ # 類型幫助信息 'Class1 Doc.' >>> Class1.__name__ # 類型名稱 'Class1' >>> Class1.__module__ # 類型所在模塊 '__main__' >>> Class1.__bases__ # 類型所繼承的基類 (<type 'object'>,) >>> Class1.__dict__ # 類型字典存儲所有類型成員信息。 <dictproxy object at 0x00D3AD70> >>> Class1().__class__ # 類型 <class '__main__.Class1'> >>> Class1().__module__ # 實例類型所在模塊 '__main__' >>> Class1().__dict__ # 對象字典存儲所有實例成員信息。 {'i': 1234}
接下來是保留方法可以把保留方法分類

類的基礎方法

序號目的所編寫代碼Python 實際調用
初始化一個實例x = MyClass()x.__init__()
字符串的“官方”表現形式repr(x)x.__repr__()
字符串的“非正式”值str(x)x.__str__()
字節數組的“非正式”值bytes(x)x.__bytes__()
格式化字符串的值format(x, format_spec)x.__format__(format_spec)
  1. 對 __init__() 方法的調用發生在實例被創建 之後 。如果要控制實際創建進程請使用 __new__() 方法

  2. 按照約定 __repr__() 方法所返回的字符串爲合法的 Python 表達式。

  3. 在調用 print(x) 的同時也調用了 __str__() 方法。

  4. 由於 bytes 類型的引入而從 Python 3 開始出現

行爲方式與迭代器類似的類

序號目的所編寫代碼Python 實際調用
遍歷某個序列iter(seq)seq.__iter__()
從迭代器中獲取下一個值next(seq)seq.__next__()
按逆序創建一個迭代器reversed(seq)seq.__reversed__()
  1. 無論何時創建迭代器都將調用 __iter__() 方法。這是用初始值對迭代器進行初始化的絕佳之處。

  2. 無論何時從迭代器中獲取下一個值都將調用 __next__() 方法。

  3. __reversed__() 方法並不常用。它以一個現有序列爲參數並將該序列中所有元素從尾到頭以逆序排列生成一個新的迭代器。

計算屬性

序號目的所編寫代碼Python 實際調用
獲取一個計算屬性無條件的x.my_propertyx.__getattribute__('my_property')
獲取一個計算屬性後備x.my_propertyx.__getattr__('my_property')
設置某屬性x.my_property = valuex.__setattr__('my_property',value)
刪除某屬性del x.my_propertyx.__delattr__('my_property')
列出所有屬性和方法dir(x)x.__dir__()
  1. 如果某個類定義了 __getattribute__() 方法在 每次引用屬性或方法名稱時 Python 都調用它特殊方法名稱除外因爲那樣將會導致討厭的無限循環。

  2. 如果某個類定義了 __getattr__() 方法Python 將只在正常的位置查詢屬性時纔會調用它。如果實例 x 定義了屬性color x.color 將 不會 調用x.__getattr__('color')而只會返回x.color 已定義好的值。

  3. 無論何時給屬性賦值都會調用 __setattr__() 方法。

  4. 無論何時刪除一個屬性都將調用 __delattr__() 方法。

  5. 如果定義了 __getattr__() 或 __getattribute__() 方法 __dir__() 方法將非常有用。通常調用 dir(x) 將只顯示正常的屬性和方法。如果__getattr()__方法動態處理color 屬性 dir(x) 將不會將 color 列爲可用屬性。可通過覆蓋 __dir__() 方法允許將 color 列爲可用屬性對於想使用你的類但卻不想深入其內部的人來說該方法非常有益。

 

序號目的所編寫代碼Python 實際調用
 序列的長度len(seq)seq.__len__()
 瞭解某序列是否包含特定的值x in seqseq.__contains__(x)

 

序號目的所編寫代碼Python 實際調用
 通過鍵來獲取值x[key]x.__getitem__(key)
 通過鍵來設置值x[key] = valuex.__setitem__(key,value)
 刪除一個鍵值對del x[key]x.__delitem__(key)
 爲缺失鍵提供默認值x[nonexistent_key]x.__missing__(nonexistent_key)

 

可比較的類

我將此內容從前一節中拿出來使其單獨成節是因爲“比較”操作並不侷限於數字。許多數據類型都可以進行比較——字符串、列表甚至字典。如果要創建自己的類且對象之間的比較有意義可以使用下面的特殊方法來實現比較。

 

序號目的所編寫代碼Python 實際調用
 相等x == yx.__eq__(y)
 不相等x != yx.__ne__(y)
 小於x < yx.__lt__(y)
 小於或等於x <= yx.__le__(y)
 大於x > yx.__gt__(y)
 大於或等於x >= yx.__ge__(y)
 布爾上上下文環境中的真值if x:x.__bool__()

 

可序列化的類

 

Python 支持 任意對象的序列化和反序列化。多數 Python 參考資料稱該過程爲 “pickling” 和 “unpickling”。該技術對與將狀態保存爲文件並在稍後恢復它非常有意義。所有的 內置數據類型 均已支持 pickling 。如果創建了自定義類且希望它能夠 pickle閱讀 pickle 協議 瞭解下列特殊方法何時以及如何被調用。

 

序號目的所編寫代碼Python 實際調用
 自定義對象的複製copy.copy(x)x.__copy__()
 自定義對象的深度複製copy.deepcopy(x)x.__deepcopy__()
 在 pickling 之前獲取對象的狀態pickle.dump(x, file)x.__getstate__()
 序列化某對象pickle.dump(x, file)x.__reduce__()
 序列化某對象新 pickling 協議pickle.dump(x, fileprotocol_version)x.__reduce_ex__(protocol_version)
*控制 unpickling 過程中對象的創建方式x = pickle.load(file)x.__getnewargs__()
*在 unpickling 之後還原對象的狀態x = pickle.load(file)x.__setstate__()

 

* 要重建序列化對象Python 需要創建一個和被序列化的對象看起來一樣的新對象然後設置新對象的所有屬性。__getnewargs__() 方法控制新對象的創建過程而 __setstate__() 方法控制屬性值的還原方式。

 

可在 with 語塊中使用的類

 

with 語塊定義了 運行時刻上下文環境在執行 with 語句時將“進入”該上下文環境而執行該語塊中的最後一條語句將“退出”該上下文環境。

 

序號目的所編寫代碼Python 實際調用
 在進入 with 語塊時進行一些特別操作with x:x.__enter__()
 在退出 with 語塊時進行一些特別操作with x:x.__exit__()

 

以下是 with file 習慣用法 的運作方式

# excerpt from io.py: def _checkClosed(self, msg=None):     '''Internal: raise an ValueError if file is closed     '''     if self.closed:         raise ValueError('I/O operation on closed file.'                          if msg is None else msg)  def __enter__(self):     '''Context management protocol.  Returns self.'''     self._checkClosed()                                ①     return self                                        ②  def __exit__(self, *args):     '''Context management protocol.  Calls close()'''     self.close()                                       ③

 

  1. 該文件對象同時定義了一個 __enter__() 和一個 __exit__() 方法。該 __enter__() 方法檢查文件是否處於打開狀態如果沒有 _checkClosed()方法引發一個例外。

  2. __enter__() 方法將始終返回 self —— 這是 with 語塊將用於調用屬性和方法的對象

  3. 在 with 語塊結束後文件對象將自動關閉。怎麼做到的在 __exit__() 方法中調用了 self.close() .

 

?該 __exit__() 方法將總是被調用哪怕是在 with 語塊中引發了例外。實際上如果引發了例外該例外信息將會被傳遞給 __exit__() 方法。查閱 With 狀態上下文環境管理器 瞭解更多細節。

 

真正神奇的東西

 

如果知道自己在幹什麼你幾乎可以完全控制類是如何比較的、屬性如何定義以及類的子類是何種類型。

 

序號目的所編寫代碼Python 實際調用
 類構造器x = MyClass()x.__new__()
*類析構器del xx.__del__()
 只定義特定集合的某些屬性
x.__slots__()
 自定義散列值hash(x)x.__hash__()
 獲取某個屬性的值x.colortype(x).__dict__['color'].__get__(x, type(x))
 設置某個屬性的值x.color = 'PapayaWhip'type(x).__dict__['color'].__set__(x, 'PapayaWhip')
 刪除某個屬性del x.colortype(x).__dict__['color'].__del__(x)
 控制某個對象是否是該對象的實例 your classisinstance(x, MyClass)MyClass.__instancecheck__(x)
 控制某個類是否是該類的子類issubclass(C, MyClass)MyClass.__subclasscheck__(C)
 控制某個類是否是該抽象基類的子類issubclass(C, MyABC)MyABC.__subclasshook__(C)

 

python中以雙下劃線的是一些系統定義得名稱讓python以更優雅得語法實行一些操作本質上還是一些函數和變量與其他函數和變量無二。
比如x.__add__(y) 等價於 x+y
有一些很常見有一些可能比較偏在這裏羅列一下做個筆記備忘。
x.__contains__(y) 等價於 y in x, 在list,str, dict,set等容器中有這個函數
__base__, __bases__, __mro__, 關於類繼承和函數查找路徑的。
class.__subclasses__(), 返回子類列表
x.__call__(...) == x(...)
x.__cmp__(y) == cmp(x,y)
x.__getattribute__('name') == x.name == getattr(x, 'name'),  比__getattr__更早調用
x.__hash__() == hash(x)
x.__sizeof__(), x在內存中的字節數, x爲class得話 就應該是x.__basicsize__
x.__delattr__('name') == del x.name
__dictoffset__ attribute tells you the offset to where you find the pointer to the __dict__ object in any instance object that has one. It is in bytes.
__flags__, 返回一串數字用來判斷該類型能否被序列化if it's a heap type), __flags__ & 512
S.__format__, 有些類有用
x.__getitem__(y) == x[y], 相應還有__setitem__, 某些不可修改類型如setstr沒有__setitem__
x.__getslice__(i, j) == x[i:j], 有個疑問x='123456789', x[::2],是咋實現得
__subclasscheck__(), check if a class is subclass
__instancecheck__(), check if an object is an instance
__itemsize__, These fields allow calculating the size in bytes of instances of the type. 0是可變長度 非0則是固定長度
x.__mod__(y) == x%y, x.__rmod__(y) == y%x
x.__module__ , x所屬模塊
x.__mul__(y) == x*y,  x.__rmul__(y) == y*x

__reduce__, __reduce_ex__ , for pickle

__slots__ 使用之後類變成靜態一樣沒有了__dict__, 實例也不可新添加屬性

__getattr__ 在一般的查找屬性查找不到之後會調用此函數

__setattr__ 取代一般的賦值操作如果有此函數會調用此函數 如想調用正常賦值途徑用 object.__setattr__(self, name, value)

__delattr__ 同__setattr__, 在del obj.name有意義時會調用


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章