天天看點

8.python之面相對象part.6(python面向對象之封裝的概念)

一.什麼是封裝?

對于什麼是封裝,我找到了一個很好的例子...就不在這裡做解釋了,以下内容來源于峰氏理論...與部落客無關....

(下面内容轉載自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,如需轉載請自行聯系原作者