python單下劃線/雙下劃線使用總結

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()

轉載註明地址:http://www.chengxuyuans.com/Python/67370.html


-------------------------

設f爲類的實例,_halfprivate()  __private()爲該類的方法:

_開頭的是半私有;外部可以訪問比如f._halfprivate(),不建議這麼用。

__開頭的是全私有:外部訪問 f.__private()     會報error錯誤。

沒有下劃線開頭的方法都是公有方法,外部內部隨便調用!

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