淺談python 里面的單下劃線與雙下劃線的區(qū)別
在學(xué)習(xí)Python的時(shí)候,很多人都不理解為什么在方法(method)前面會(huì)加好幾個(gè)下劃線,有時(shí)甚至兩邊都會(huì)加,比如像 __this__ 這種。在我看到上面的文章之前,我一直以為Python中這些下劃線的作用就像Golang中方法/函數(shù)的大小寫一樣,或是一些其他語言中的 private 、 public 的作用一樣,但仔細(xì)深究,這不全是Python這樣設(shè)計(jì)的初衷。下面我們具體分析。
主要存在四種命名
1. object # 公用方法
2. __object__ # 內(nèi)建方法,用戶不要這樣定義
3. __object # 全私有,全保護(hù)
4. _object # 半保護(hù)
核心風(fēng)格:避免用下劃線作為變量名的開始。
因?yàn)橄聞澗€對(duì)解釋器有特殊的意義,而且是內(nèi)建標(biāo)識(shí)符所使用的符號(hào),我們建議程序員避免用下劃線作為變量名的開始。一般來講,變量名_object被看作是“私有的”,在模塊或類外不可以使用,不能用'from module import *'導(dǎo)入。當(dāng)變量是私有的時(shí)候,用_object來表示變量是很好的習(xí)慣。
單下劃線+類名,eg:_Class__object 機(jī)制就可以訪問__object__了。因?yàn)樽兞棵鸰_object__對(duì)Python 來說有特殊含義,對(duì)于普通的變量應(yīng)當(dāng)避免這種命名風(fēng)格。
“單下劃線” 開始的成員變量叫做保護(hù)變量,意思是只有類對(duì)象和子類對(duì)象自己能訪問到這些變量;”雙下劃線” 開始的是私有成員,意思是只有類對(duì)象自己能訪問,連子類對(duì)象也不能訪問到這個(gè)數(shù)據(jù)。(如下列所示)
以單下劃線開頭_foo的代表不能直接訪問的類屬性,需通過類提供的接口進(jìn)行訪問,不能用“from xxx import *”而導(dǎo)入;以雙下劃線開頭的__foo代表類的私有成員;以雙下劃線開頭和結(jié)尾的__foo__代表python里特殊方法專用的標(biāo)識(shí),如 __init__()代表類的構(gòu)造函數(shù)。
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()可以直接訪問,確實(shí)是。不過根據(jù)python的約定,應(yīng)該將其視作private,而不要在外部使用它們,(如果你非要使用也沒轍),良好的編程習(xí)慣是不要在外部使用它。同時(shí),根據(jù)Python docs的說明,_object和__object的作用域限制在本模塊內(nèi)。
大家看下面這段程序的輸出:
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有個(gè)名為_A__private的 屬性呢?而且__private消失了!這就要談?wù)凱ython的私有變量“矯直”了。
Python把以兩個(gè)或以上下劃線字符開頭且沒有以兩個(gè)或以上下劃線結(jié)尾的變量當(dāng)作私有變量。私有變量會(huì)在代碼生成之前被轉(zhuǎn)換為長(zhǎng)格式(變?yōu)楣校?。轉(zhuǎn)換機(jī)制是這樣的:在變量前端插入類名,再在前端加入一個(gè)下劃線字符。這就是所謂的私有變量矯直(Private name mangling)。如類 A里的__private標(biāo)識(shí)符將被轉(zhuǎn)換為_A__private,這就是上一節(jié)出現(xiàn)_A__private和__private消失的原因了。
再講兩點(diǎn)題外話:
一是因?yàn)槌C直會(huì)使標(biāo)識(shí)符變長(zhǎng),當(dāng)超過255的時(shí)候,Python會(huì)切斷,要注意因此引起的命名沖突。
二是當(dāng)類名全部以下劃線命名的時(shí)候,Python就不再執(zhí)行矯直。如:
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() # 可以外部調(diào)用 ____.__method()
現(xiàn)在我們回過頭來看看為什么會(huì)輸出“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()'
因?yàn)樵陬怋定義的時(shí)候沒有覆蓋__init__方法,所以調(diào)用的仍然是A.__init__,即執(zhí)行了self._A__private(),自然輸出“A.__private()”了。
下面的兩段代碼可以增加說服力,增進(jìn)理解:
class C(A): def __init__(self): # 重寫 __init__ ,不再調(diào)用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() # 調(diào)用一個(gè)沒有定義的函數(shù),但可執(zhí)行 self.public() def __private(self): print 'A.__private()' def public(self): print 'A.public()' a = A() 答案: A.__private() A.public()
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
opencv python 圖像輪廓/檢測(cè)輪廓/繪制輪廓的方法
這篇文章主要介紹了opencv python 圖像輪廓/檢測(cè)輪廓/繪制輪廓的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07python進(jìn)階從青銅到王者一定會(huì)用上的Python技巧
這篇文章主要介紹了python進(jìn)階從青銅到王者一定會(huì)用上的Python技巧,本文通過幾個(gè)Python的小案例,讓大家體會(huì)其中蘊(yùn)含的技巧一起來圍觀吧2021-09-09基于Opencv圖像識(shí)別實(shí)現(xiàn)答題卡識(shí)別示例詳解
這篇文章主要為大家詳細(xì)介紹了基于OpenCV如何實(shí)現(xiàn)答題卡識(shí)別,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Python實(shí)現(xiàn)批量提取Word文檔表格數(shù)據(jù)
在大數(shù)據(jù)處理與信息抽取領(lǐng)域中,Word文檔是各類機(jī)構(gòu)和個(gè)人普遍采用的一種信息存儲(chǔ)格式,本文將介紹如何使用Python實(shí)現(xiàn)對(duì)Word文檔中表格的提取,感興趣的可以了解下2024-03-03Django中URL的參數(shù)傳遞的實(shí)現(xiàn)
這篇文章主要介紹了Django中URL的參數(shù)傳遞的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08