python 單底線/雙底線使用總結

來源:互聯網
上載者:User
Python 用底線作為變數首碼和尾碼指定特殊變數/方法。

主要存在四種情形
1. 1. object # public
2. __object__ # special, python system use, user should not define like it
3. __object # private (name mangling during runtime)
4. _object # obey python coding convention, consider it as private
核心風格:避免用底線作為變數名的開始。

因為底線對解譯器有特殊的意義,而且是內建標識符所使用的符號,我們建議程式員避免用底線作為變數名的開始。一般來講,變數名_object被看作是“私人 的”,在模組或類外不可以使用,不能用'from moduleimport *'匯入。當變數是私人的時候,用_object來表示變數是很好的習慣。因為變數名__object__對Python 來說有特殊含義,對於普通的變數應當避免這種命名風格。

python有關private的描述,python中不存在protected的概念,要麼是public要麼就是private,但是python中的private不像C++, Java那樣,它並不是真正意義上的private,通過name mangling(名稱改編(目的就是以防子類意外重寫基類的方法或者屬性),即前面加上“單底線”+類名,eg:_Class__object)機制就可以訪問private了。

"單底線" 開始的成員變數叫做保護變數,意思是只有類對象和子類對象自己能訪問到這些變數;"雙底線" 開始的是私人成員,意思是只有類對象自己能訪問,連子類對象也不能訪問到這個資料。(如下列所示)
以單底線開頭(_foo)的代表不能直接存取的類屬性,需通過類提供的介面進行訪問,不能用“from xxx import *”而匯入;以雙底線開頭的(__foo)代表類的私人成員;以雙底線開頭和結尾的(__foo__)代表python裡特殊方法專用的標識,如 __init__()代表類的建構函式。

1.class Foo():

2. def __init__():
3. ...
4.
5. def public_method():
6. print 'This is public method'
7.
8. def __fullprivate_method():
9. print 'This is double underscore leading method'
10.
11. def _halfprivate_method():
12. print 'This is one underscore leading method'
執行個體化Foo的一個對象,

1. f = Foo()
1. f.public_method() # OK
2.
3. f.__fullprivate_method() # Error occur
4.
5. f._halfprivate_method() # OK
6.
7. f._Foo__fullprivate()_method() # OK

從上面的例子可以看出,f._halfprivate_method()可以直接存取,確實是。不過根據python的約定,應該將其視作private,而不要在外部使用它們,(如果你非要使用也沒轍),良好的編程習慣是不要在外部使用它。同時,根據Python docs的說明,_object和__object的範圍限制在本模組內。

==============================================================================
理解Python命名機制(單雙底線開頭) (轉載:http://blog.csdn.net/lanphaday)
引子
我熱情地邀請大家猜測下面這段程式的輸出:
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.__private()”開始。但要講清楚為什麼,我們就有必要瞭解一下Python的命名機制。
據 Python manual,變數名(標識符)是Python的一種原子項目。當變數名被綁定到一個對象的時候,變數名就指代這個對象,就像人類社會一樣,不是嗎?當變 量名出現在代碼塊中,那它就是本地變數;當變數名出現在模組中,它就是全域變數。模組相信大家都有很好的理解,但代碼塊可能讓人費解些。在這裡解釋一下:
代碼塊就是可作為可執行單元的一段Python程式文本;模組、函數體和類定義都是代碼塊。不僅如此,每一個互動指令碼命令也是一個代碼塊;一個指令檔也是一個代碼塊;一個命令列指令碼也是一個代碼塊。
接下來談談變數的可見度,我們引入一個範圍的概念。範圍就是變數名在代碼塊的可見度。 如果一個代碼塊裡定義本地變數,那範圍就包括這個代碼塊。如果變數定義在一個功能代碼塊裡,那範圍就擴充到這個功能塊裡的任一代碼塊,除非其中定義了同名 的另一變數。但定義在類中的變數的範圍被限定在類代碼塊,而不會擴充到方法代碼塊中。
迷蹤
據上節的理論,我們可以把代碼分為三個代碼塊:類A的定義、類B的定義和變數b的定義。根據類定義,我們知道代碼給類A定義了三個成員變數(Python的函數也是對象,所以成員方法稱為成員變數也行得通。);類B定義了兩個成員變數。這可以通過以下代碼驗證:
>>> print '\n'.join(dir(A))
_A__private
__init__
public
>>> print '\n'.join(dir(B))
_A__private
_B__private
__init__
public
咦,為什麼類A有個名為_A__private的 Attribute 呢?而且__private消失了!這就要談談Python的私人變數軋壓了。
探究
懂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()”吧!
真相
相信現在聰明的讀者已經猜到答案了吧?如果你還沒有想到,我給你個提示:真相跟C語言裡的宏預先處理差不多。
因為類A定義了一個私人成員函數(變數),所以在代碼產生之前先執行私人變數軋壓(注意到上一節標紅的那行字沒有?)。軋壓之後,類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()'
是不是有點像C語言裡的宏展開啊?
因為在類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() # 調用一個沒有定義的函數, Python 會把它給我的
self.public()
def __private(self):
print 'A.__private()'
def public(self):
print 'A.public()'
>>>a = A()
A.__private()
A.public()
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.