淺談python 裡面的單底線與雙底線的區別,淺談python
在學習Python的時候,很多人都不理解為什麼在方法(method)前面會加好幾個底線,有時甚至兩邊都會加,比如像 __this__ 這種。在我看到上面的文章之前,我一直以為Python中這些底線的作用就像Golang中方法/函數的大小寫一樣,或是一些其他語言中的 private 、 public 的作用一樣,但仔細深究,這不全是Python這樣設計的初衷。下面我們具體分析。
主要存在四種命名
1. object # 公用方法
2. __object__ # 內建方法,使用者不要這樣定義
3. __object # 全私人,全保護
4. _object # 半保護
核心風格:避免用底線作為變數名的開始。
因為底線對解譯器有特殊的意義,而且是內建標識符所使用的符號,我們建議程式員避免用底線作為變數名的開始。一般來講,變數名_object被看作是“私人的”,在模組或類外不可以使用,不能用'from module import *'匯入。當變數是私人的時候,用_object來表示變數是很好的習慣。
單底線+類名,eg:_Class__object 機制就可以訪問__object__了。因為變數名__object__對Python 來說有特殊含義,對於普通的變數應當避免這種命名風格。
“單底線” 開始的成員變數叫做保護變數,意思是只有類對象和子類對象自己能訪問到這些變數;”雙底線” 開始的是私人成員,意思是只有類對象自己能訪問,連子類對象也不能訪問到這個資料。(如下列所示)
以單底線開頭_foo的代表不能直接存取的類屬性,需通過類提供的介面進行訪問,不能用“from xxx import *”而匯入;以雙底線開頭的__foo代表類的私人成員;以雙底線開頭和結尾的__foo__代表python裡特殊方法專用的標識,如 __init__()代表類的建構函式。
class Foo(): def __init__(): ... def public_method(): print 'This is public method' def __fullprivate_method(): print 'This is fullprivate_method' def _halfprivate_method(): print 'This is halfprivate_method' f = Foo() f.public_method() # OK f.__fullprivate_method() # Error occur f._halfprivate_method() # OK f._Foo__fullprivate_method() # OK
從上面的例子可以看出,f._halfprivate_method()可以直接存取,確實是。不過根據python的約定,應該將其視作private,而不要在外部使用它們,(如果你非要使用也沒轍),良好的編程習慣是不要在外部使用它。同時,根據Python docs的說明,_object和__object的範圍限制在本模組內。
大家看下面這段程式的輸出:
class A(object): def __init__(self): self.__private() self.public() def __private(self): print 'A.__private()' def public(self): print 'A.public()'class B(A): def __private(self): print 'B.__private()' def public(self): print 'B.public()'b = B()
初探
正確的答案是:
A.__private()
B.public()
我們分別看下類A和類B的屬性都有哪些:
>>> print '\n'.join(dir(A))_A__private__init__public>>> print '\n'.join(dir(B))_A__private_B__private__init__public
為什麼類A有個名為_A__private的 屬性呢?而且__private消失了!這就要談談Python的私人變數“矯直”了。
Python把以兩個或以上底線開頭且沒有以兩個或以上底線結尾的變數當作私人變數。私人變數會在代碼產生之前被轉換為長格式(變為公有)。轉換機制是這樣的:在變數前端插入類名,再在前端加入一個底線。這就是所謂的私人變數矯直(Private name mangling)。如類 A裡的__private標識符將被轉換為_A__private,這就是上一節出現_A__private和__private消失的原因了。
再講兩點題外話:
一是因為矯直會使標識符變長,當超過255的時候,Python會切斷,要注意因此引起的命名衝突。
二是當類名全部以底線命名的時候,Python就不再執行矯直。如:
class ____(object): def __init__(self): self.__method() def __method(self): print '____.__method()'print '\n'.join(dir(____))__class____delattr____dict____doc____getattribute____hash____init____method # 沒被矯直__module____new____reduce____reduce_ex____repr____setattr____str____weakref__obj = ____()____.__method()obj.__method() # 可以外部調用____.__method()
現在我們回過頭來看看為什麼會輸出“A.__private()”吧!
矯直之後,類A的代碼就變成這樣了:
class A(object): def __init__(self): self._A__private() # 這行變了 self.public() def _A__private(self): # 這行也變了 print 'A.__private()' def public(self): print 'A.public()'
因為在類B定義的時候沒有覆蓋__init__方法,所以調用的仍然是A.__init__,即執行了self._A__private(),自然輸出“A.__private()”了。
下面的兩段代碼可以增加說服力,增進理解:
class C(A): def __init__(self): # 重寫 __init__ ,不再調用self._A__private self.__private()# 這裡綁定的是 _C_private self.public() def __private(self): print 'C.__private()' def public(self): print 'C.public()'c = C()答案:C.__private()C.public()
class A(object): def __init__(self): self._A__private() # 調用一個沒有定義的函數,但可執行 self.public() def __private(self): print 'A.__private()' def public(self): print 'A.public()'a = A()答案:A.__private()A.public()
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。