1. 程式人生 > >python_面向對象之多態、封裝

python_面向對象之多態、封裝

python python面向對象 面向對象多態、封裝特性

多態
一.定義
多態:有不同的類實例化得到的對象,調用不同的方法,執行的邏輯不同。
類的繼承有兩層意義:1.改變,2.擴展。多態就是類的兩層意義的一個具體的實現機制,即:調用不同的類實例化的對象下的相同方法,實現的過程不一樣。
一.封裝
封裝可以理解為一個多功能的自助飲料機器,且機器是不透明密封的,只在下方開了不同的龍頭,當顧客需要不同的飲料時,只需要去打開不同的龍頭開關即可得到自己想要的飲料,但顧客不知道機器內部是產生不同的飲料的。
在python中,封裝可以是類,可以是函數。封裝是將數據或屬性隱藏在內部,不讓外部看到。
二.封裝的使用
類的封裝兩個層面,第一個層面的封裝:類就是一個容器,這本身就是一種封裝;第二個層面的封裝:類中定義私有的屬性,只在類的內部使用,外部無法訪問。
Python中不依賴語言特征去實現第二個層面的封裝,而是通過遵守一定的數據屬性和函數屬性的命名約定來達到封裝的效果。
約定1.任何以雙下劃線開頭的名字都應該是類內部私有的屬性,外部無法訪問。如下圖:
技術分享圖片
這是調用類私有的數據屬性,如果調用類私有的函數屬性呢?結果見下圖:
技術分享圖片
從上面的例子,我們可以發現:類中雙下劃線命名的所有屬性(包含:數據屬性和函數屬性)在外部均不能正常訪問。
那麽外部是不是真的就不能訪問內部的數據屬性呢?我們先打印類的屬性字典,此時會發現類中的以雙下劃線開頭的leadteacher數據屬性和activy均發生了改變,如下圖所示:
技術分享圖片
至此我們發現:此時在對應的雙下劃線的屬性下面加上了_類名,那麽是不是就有辦法在外部來進行訪問了呢?如下圖:
技術分享圖片

總結:以單下劃線或雙下劃線命名的屬性,只是一種約定,並不是說python一定不能訪問。實際上,python並不會真的阻止你訪問私有的屬性,模塊也是這種約定。

那麽,子類繼承父類後,子類是否可以訪問父類私有的屬性呢?見下圖:
技術分享圖片
封裝的第三個層面:明確區分內外,內部的實現邏輯,外部無法知曉,並且為封裝到內部的邏輯他提供一個訪問接口給外部使用(這才是真正的封裝),封裝的含義就是將類內部的屬性隱藏起來,但是外部如果要使用它怎麽辦?這是就用到了第三個層面的封裝了,我們可以在類的類別定義一個函數調用雙下劃線的屬性,這樣我們通過調用這個函數就可以間接的訪問類中隱藏的屬性了。改寫上面的例子,見下圖:
技術分享圖片
該部分的代碼塊為:

class School():
    price = 12000
    __leadteacher = "劉昌明"   #雙下劃線開頭的數據屬性
    def __init__(self,name,addr,type):
        self.name = name
        self.addr = addr
        self.type = type

    def showinfo(self):
        print("%s位於%s,是一所%大學,學費是%s"%(self.name,self.addr,self.type,self.price))

    def __activy(self):
        print("學校正在舉辦書法比賽")

    def returninfo(self):           #通過類中的函數來訪問隱藏的屬性,以供外部調用,這才是真正意義上的封裝
        print("這個學校的現在是%s"%self.__leadteacher)
        self.__activy()

# class Student(School):
#     print(School.__leadteacher)
s1 =School("長江大學","湖北省荊州市","國立一本")

#直接在外部訪問類的數據屬性
# print(s1.price)
# print(s1.__leadteacher)   #報錯
# print(s1._leadteacher)   #報錯
#直接在外部訪問類的函數屬性
# s1.__activy()     #報錯
#打印類的屬性字典
# print(School.__dict__)
#再次訪問類的內部屬性
# print(s1._School__leadteacher)
# s1._School__activy()
# student = Student()
#通過類中的接口函數來訪問類中隱藏的屬性
s1.returninfo()

python_面向對象之多態、封裝