python下劃線,私有變數
阿新 • • 發佈:2018-11-03
轉自:http://blog.sina.com.cn/s/blog_58649eb30100g4zo.html
Python用下劃線作為變數字首和字尾指定特殊變數。
"
單下劃線" 開始的成員變數叫做保護變數,意思是隻有類物件和子類物件自己能訪問到這些變數;
不能用“from xxx import *”而匯入;
" 雙下劃線" 開始的是私有成員,意思是 只有類物件自己能訪問,連子類物件也不能訪問到這個資料。
以 雙下劃線開頭和結尾的代表python裡 特殊方法專用的標識,如 __init__()代表類的建構函式。
核心風格:避免用下劃線作為變數名的開始。
因為下劃線對直譯器有特殊的意義,而且是內建識別符號所使用的符號,建議避免用下劃線作為變數名的開始。
A.__private()
B.public()
為什麼會有上述輸出呢?
我們先看一個小測試:
[' _A__private', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'public']
可以看到,類A有個名為_A__private的 Attribute,而且__private消失了!這就要談談 Python的私有變數軋壓了。
如果我們輸入:
b.__private()
得到的將是:
AttributeError: 'B' object has no attribute '__private'
也就是說 私有變數__foo經過mangle成為_ClassName__foo後繼承給了子類。
Python把 以兩個下劃線開頭且沒有以兩個下劃線結尾的變數當作私有變數。
私有變數會在程式碼生成之前被轉換為長格式(變為公有)。
轉換機制是這樣的:在變數前端插入類名,再在前端加入一個下劃線字元。這就是所謂的 私有變數軋壓(Private name mangling)。
如類A裡的__private識別符號將被轉換為_A__private,這就是前面的小測試出現_A__private,而__private消失的原因了。
注意下面2點:
一是因為軋壓會使識別符號變長,當超過255的時候,Python會切斷,要注意因此引起的命名衝突。
二是 當類名全部以下劃線命名的時候,Python就不再執行軋壓。如:
__class__
__delattr__
__dict__
__doc__
__format__
__getattribute__
__hash__
__init__
__method #沒有被軋壓
__module__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
____.__method()
____.__method()
現在我們回過頭來看看文章開頭為什麼會輸出“A.__private()”吧!這跟C語言裡的巨集預處理差不多。
因為類A定義了一個私有成員函式(變數),所以在程式碼生成之前先執行私有變數軋壓。軋壓之後,類A的程式碼就變成這樣了:
因為在類B定義的時候沒有覆蓋__init__方法,所以呼叫的仍然是A.__init__,即執行了self._A__private(),自然輸出“A.__private()”了。
下面我們再看一個例子:
C.__private()
C.public()
最後一個例子:
[' _A__private', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'public']
A.__private()
A.public()
" 雙下劃線" 開始的是私有成員,意思是 只有類物件自己能訪問,連子類物件也不能訪問到這個資料。
以 雙下劃線開頭和結尾的代表python裡 特殊方法專用的標識,如 __init__()代表類的建構函式。
核心風格:避免用下劃線作為變數名的開始。
因為下劃線對直譯器有特殊的意義,而且是內建識別符號所使用的符號,建議避免用下劃線作為變數名的開始。
觀察下面這段程式的輸出:
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()
為什麼會有上述輸出呢?
我們先看一個小測試:
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()' print dir(A)
執行結果:
[' _A__private', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'public']
可以看到,類A有個名為_A__private的 Attribute,而且__private消失了!這就要談談 Python的私有變數軋壓了。
如果我們輸入:
b.__private()
得到的將是:
AttributeError: 'B' object has no attribute '__private'
也就是說 私有變數__foo經過mangle成為_ClassName__foo後繼承給了子類。
Python把 以兩個下劃線開頭且沒有以兩個下劃線結尾的變數當作私有變數。
私有變數會在程式碼生成之前被轉換為長格式(變為公有)。
轉換機制是這樣的:在變數前端插入類名,再在前端加入一個下劃線字元。這就是所謂的 私有變數軋壓(Private name mangling)。
如類A裡的__private識別符號將被轉換為_A__private,這就是前面的小測試出現_A__private,而__private消失的原因了。
注意下面2點:
一是因為軋壓會使識別符號變長,當超過255的時候,Python會切斷,要注意因此引起的命名衝突。
二是 當類名全部以下劃線命名的時候,Python就不再執行軋壓。如:
class ____(object): def __init__(self): self.__method() def __method(self): print '____.__method()' print '\n'.join(dir(____)) instance=____() instance.__method()#外界可以呼叫私有方法(因為沒有被軋壓)執行結果:
__class__
__delattr__
__dict__
__doc__
__format__
__getattribute__
__hash__
__init__
__method #沒有被軋壓
__module__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
____.__method()
____.__method()
現在我們回過頭來看看文章開頭為什麼會輸出“A.__private()”吧!這跟C語言裡的巨集預處理差不多。
因為類A定義了一個私有成員函式(變數),所以在程式碼生成之前先執行私有變數軋壓。軋壓之後,類A的程式碼就變成這樣了:
class A(object): def __init__(self): self.<span style="color:#ff0000;">_A__private()</span> # 這行變了 self.public() def <span style="color:#ff0000;">_A__private</span>(self): # 這行也變了 print 'A.__private()' def public(self): print 'A.public()'是不是有點像C語言裡的巨集展開啊?
因為在類B定義的時候沒有覆蓋__init__方法,所以呼叫的仍然是A.__init__,即執行了self._A__private(),自然輸出“A.__private()”了。
下面我們再看一個例子:
class A(): def __init__(self): self.__private() self.public() def __private(self): print 'A.__private()' def public(self): print 'A.public()' class C(A): def __init__(self): # 重寫__init__ 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):#該方法會被軋壓成_A__private print 'A.__private()' def public(self): print 'A.public()' print dir(A)#可以看到,軋壓後,_A__private 方法出現了! a=A()
執行結果:
[' _A__private', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'public']
A.__private()
A.public()