一.什麼是封裝?
對于什麼是封裝,我找到了一個很好的例子...就不在這裡做解釋了,以下内容來源于峰氏理論...與部落客無關....
(下面内容轉載自egon的部落格)
你錢包的有多少錢(資料的封裝)
你的性取向(資料的封裝)
你撒尿的具體功能是怎麼實作的(方法的封裝)
二.為什麼要封裝?
封裝資料的主要原因是:保護隐私(作為男人的你,臉上就寫着:我喜歡男人,你害怕麼?)
封裝方法的主要原因是:隔離複雜度(快門就是傻瓜相機為傻瓜們提供的方法,該方法将内部複雜的照相功能都隐藏起來了,比如你不必知道你自己的尿是怎麼流出來的,你直接掏出自己的接口就能用尿這個功能)
你的身體沒有一處不展現着封裝的概念:你的身體把膀胱尿道等等這些尿的功能隐藏了起來,然後為你提供一個尿的接口就可以了(接口就是你的。。。,),你總不能把膀胱挂在身體外面,上廁所的時候就跟别人炫耀:hi,man,你瞅我的膀胱,看看我是怎麼尿的。還有你的頭把你的腦子封裝到了腦殼裡,然後提供了眼睛這個接口....
提示:在程式設計語言裡,對外提供的接口(接口可了解為了一個入口),就是函數,稱為接口函數,這與接口的概念還不一樣,接口代表一組接口函數的集合體。
三.封裝分為兩個層面。
封裝其實分為兩個層面,但無論哪種層面的封裝,都要對外界提供好通路你内部隐藏内容的接口(接口可以了解為入口,有了這個入口,使用者無需且不能夠直接通路到内部隐藏的細節,隻能走接口,并且我們可以在接口的實作上附加更多的處理邏輯,進而嚴格控制使用者的通路)
第一個層面的封裝(什麼都不用做):建立類和對象會分别建立二者的名稱空間,我們隻能用類名.或者obj.的方式去通路裡面的名字,這本身就是一種封裝
>>> r1.nickname
'草叢倫'
>>> Riven.camp
'Noxus'
注意:對于這一層面的封裝(隐藏),類名.和執行個體名.就是通路隐藏屬性的接口
第二個層面的封裝:類中把某些屬性和方法隐藏起來(或者說定義成私有的),隻在類的内部使用、外部無法通路,或者留下少量接口(函數)供外部通路。
在python中用雙下劃線的方式實作隐藏屬性(設定成私有的)
類中所有雙下劃線開頭的名稱如__x都會自動變形成:_類名__x的形式:
複制代碼
class A:
__N=0 #類的資料屬性就應該是共享的,但是文法上是可以把類的資料屬性設定成私有的如__N,會變形為_A__N
def __init__(self):
self.__X=10 #變形為self._A__X
def __foo(self): #變形為_A__foo
print('from A')
def bar(self):
self.__foo() #隻有在類内部才可以通過__foo的形式通路到.
這種自動變形的特點:
1.類中定義的__x隻能在内部使用,如self.__x,引用的就是變形的結果。
2.這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字通路到的。
2.在子類定義的__x不會覆寫在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆寫的。
注意:對于這一層面的封裝(隐藏),我們需要在類中定義一個函數(接口函數)在它内部通路被隐藏的屬性,然後外部就可以使用了
也可以用6.4所講的特性property來解決,即将介紹
這種變形需要注意的問題是:
1.這種機制也并沒有真正意義上限制我們從外部直接通路屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然後就可以通路了,如a._A__N
>>> a=A()
>>> a._A__N
>>> a._A__X
10
>>> A._A__N
2.變形的過程隻在類的定義是發生一次,在定義後的指派操作,不會變形
3.在繼承中,父類如果不想讓子類覆寫自己的方法,可以将方法定義為私有的
#正常情況
>>> class A:
... def fa(self):
... print('from A')
... def test(self):
... self.fa()
...
>>> class B(A):
... print('from B')
>>> b=B()
>>> b.test()
from B
#把fa定義成私有的,即__fa
... def __fa(self): #在定義時就變形為_A__fa
... self.__fa() #隻會與自己所在的類為準,即調用_A__fa
... def __fa(self):
from A
python并不會真的阻止你通路私有的屬性,子產品也遵循這種約定,如果子產品名以單下劃線開頭,那麼from module import *時不能被導入,但是你from module import _private_module依然是可以導入的
其實很多時候你去調用一個子產品的功能時會遇到單下劃線開頭的(socket._socket,sys._home,sys._clear_type_cache),這些都是私有的,原則上是供内部調用的,作為外部的你,一意孤行也是可以用的,隻不過顯得稍微傻逼一點點
python要想與其他程式設計語言一樣,嚴格控制屬性的通路權限,隻能借助内置方法如__getattr__,詳見面向對象進階。
本文轉自蘇浩智 51CTO部落格,原文連結:http://blog.51cto.com/suhaozhi/1917932,如需轉載請自行聯系原作者