🍖類的封裝

引入

先來舉個例子 :

當你摁下電腦開機鍵, 你不須要考慮主板是怎麼通電的、 磁盤是怎麼轉動的、系統的信息是怎麼加載的、裏面的一系列化學或者物理變化是怎麼樣的,你面對的就是一個開關鍵, 摁下它, 電腦就開起來了.python

v2-cfc14c7293afd962ecbd1dc31dafd002

又好比:

一個玩具製造廠, 製做一個機器人, 咱們須要去考慮機器人的每個細節: 手臂、腿、頭、軀幹等等,製做簡單的玩具沒關係, 若是設計的玩具很是的複雜, 而且這工廠還有不少其餘類型的玩具生產(小熊, 佩奇, 芭比公主,飛機模型等等)安全

497915717af56b63a5454a26b127916

上面咱們使用面向過程的思想去設計, 在程序中就會讓咱們的代碼很長, 很雜亂數據結構

因而工廠聽取了小王的建議, 引進了一臺製造機器人玩具的機器, 咱們只須要摁下機器的開關, 它就會自動製造機器人函數

這個時候咱們再也不去關注是先製造手仍是腳仍是軀幹這些細節, 咱們面對的就只是一臺機器, 這機器就是一個對象設計

原理 : 之前咱們須要關注製做玩具的每一個步驟, 如今咱們將步驟都封裝到一個機器裏面, 留給咱們的只剩一個開關, 咱們只須要摁開關就能夠生產玩具了, 這就是面向對象的三大特性之一 : 封裝, 下面咱們將詳細展開介紹code

一.封裝

1.什麼封裝

  • 封裝是Python中面向對象的三大特性之一
  • 封裝就是隱藏對象的屬性和實現細節, 僅對外提供公共訪問方式

2.爲何使用封裝

  • 提升安全性 : 避免用戶對類中屬性或方法進行不合理的操做
  • 隔離複雜度 : 就以上面的例子爲例, 你只須要機器提供給你的開關, 內部結構不須要知道
  • 保證內部數據結構完整性 : 很好的避免了外部對內部數據的影響,提升了程序的可維護性
  • 提供代碼的複用性

3.封裝的原則

  • 將不須要對外提供的功能都給隱藏起來
  • 把屬性都隱藏, 提供公共方法對其方法

二.隱藏

在python中用雙下劃線開頭的方式將屬性隱藏起來(設置成私有的)對象

  • 其實這僅僅這是一種變形操做且僅僅只在類定義階段發生變形
  • 類中全部雙下劃線開頭的名稱如__xxx都會在類定義時自動變造成:_[類名]__xxx的形式
class Eat:
    __breed = "五花肉"        # 變形 : "_Eat__breed"

    def __init__(self):     
        self.__meat = "大塊"  # 變形 : "_Eat__meat"

    def __eat(self):          # 變形 : "_Eat__eat"
        print(f"吃了{self.__meat}的{self.__breed}")

    def eat_meat(self):
        self.__eat()          # 只有在類的內部才能夠經過"__eat"的形式訪問到

P1 = Eat()

🍔調用類提供的接口(方法)
P1.eat_meat()      # 吃了大塊的五花肉

🍔調用隱藏的屬性/方法,報錯
print(P1.breed)    # 報錯 "AttributeError" 沒有該屬性
print(P1.__breed)  # 報錯 "AttributeError" 沒有該屬性
P1.__eat()         # 報錯 "AttributeError" 沒有該屬性

🍔調用變形後的屬性/方法(不推薦這麼作)
print(P1._Eat__breed)  # 五花肉
print(P1._Eat__meat)   # 大塊
P1._Eat__eat()         # 吃了大塊的五花肉

三.封裝的兩個層面

1.第一層面(公有 : public)

  • **public **: 公有屬性的類變量和類函數,在類的外部、類內部以及子類中,均可以正常訪問
🍔咱們來製做一個機器人,分別要考慮製做不一樣部件,每一個方法都得調用一下
class Rebot:
    def Head(self):
        print("製做頭")

    def Hand(self):
        print("製做手")

    def Foot(self):
        print("製做腳")

    def Body(self):
        print("製做軀幹")

    def Fit(self):
        print("機器人合體")

P1 = Rebot()

🍔沒有進行封裝,咱們須要進行每個部件的調用
P1.Hand()  # 製做手
P1.Head()  # 製做頭
P1.Foot()  # 製做腳
P1.Body()  # 製做軀幹
P1.Fit()   # 機器人合體

🍔當咱們進行封裝,提供給用戶一個"Auto"接口(方法)
    def Auto(self):  # 提示:這個Auto方法是在類裏面的,方便講解我才放在這個位置
        self.Hand()
        self.Head()
        self.Foot()
        self.Body()
        self.Fit()
        
🍔用戶只須要調用"Auto"這個方法就能夠一步完成上面的全部步驟
P1.Auto()
'''輸出
製做手
製做頭
製做腳
製做軀幹
機器人合體
'''

若是這樣的話, 使用者仍是能夠調用裏面機器人的製做細節, 若是咱們不想讓使用者使用到那些方法, 咱們就能夠將細節部分給隱藏起來, 只提供一個"Auto"方法,👇👇接口

2.第二層面 (私有 : private)

  • private:私有屬性的類變量和類函數,只有在類的內部使用,類的外部以及子類都沒法使用
    • 若是類中的變量和函數,其名稱以雙下劃線__開頭,則該變量或函數爲私有的
    • 若是以單下劃線_開頭的屬性和方法,咱們約定俗成的視其爲私有, 就是上面隱藏裏說到的變形後的結果, 雖然能正常調用, 但不建議這麼作
class Rebot:
    def __Head(self):    # 變形 : "_Rebot__Head"
        print("製做頭")

    def __Hand(self):    # 變形 : "_Rebot__Hand"
        print("製做手")

    def __Foot(self):    # 變形 : "_Rebot__Foot"
        print("製做腳")

    def __Body(self):    # 變形 : "_Rebot__Body"
        print("製做軀幹")

    def __Fit(self):     # 變形 : "_Rebot__Fit"
        print("機器人合體")

    def Auto(self):      # 提供給使用者的接口(方法)
        self.__Hand()
        self.__Head()
        self.__Foot()
        self.__Body()
        self.__Fit()

P1 = Rebot()

P1.Auto()
'''輸出
製做手
製做頭
製做腳
製做軀幹
機器人合體
'''

# P1.__Hand()  # 報錯 : "AttributeError" 沒有該屬性
# P1.__Head()  # 報錯 : "AttributeError" 沒有該屬性

🍔若是特別想調用, 能夠這麼調用, 但很是不建議
P1._Rebot__Hand()  # 製做頭
P1._Rebot__Head()  # 製做手

如此就實現了給使用者只看到能讓他用的東西it

不給用戶直接使用的東西隱藏起來class

四.小示例

  • 定義一我的類, 而後實例出一個對象, 該對象的名字不能以 "sb" 開頭
  • "name" 這個屬性隱藏起來, 外部訪問不到
  • "name" 隱藏起來後, 對象本身該如何獲取這個屬性? 提供一個打印名字的方法
  • 定義一個修更名字的方法
class Person:
    def __init__(self,name):
        if not name.startswith("sb"):
            self.__name = name
        else:
            print("名字不能以'sb'開頭")

    def print_name(self):        # 打印名字的方法
        print(self.__name)

    def change_name(self,name):  # 修更名字的方法
        if not name.startswith("sb"):
            self.__name = name
            print("修改爲功")
        else:
            print("名字不能以'sb'開頭")

P1 = Person("sb_hahah")    # 名字不能以'sb'開頭
P2 = Person("shawn")

# print(P2.__name)         # 報錯 : "AttributeError" 沒有該屬性
# print(P2.name)           # 報錯 : "AttributeError" 沒有該屬性

P2.print_name()            # shawn

P2.change_name("sb_kkkk")  # 名字不能以'sb'開頭
P2.change_name("xing")     # 修改爲功
P2.print_name()            # xing

如此一來保證了數據的安全

補充 :

  • 模塊中也能夠使用隱藏屬性, 在屬性前加 "_", 例 : "_name" (單雙下劃線均可以)
  • 但願只在模塊內部使用, 而外部沒法使用
  • 針對的是from xxx import * 方法中的 * 星號
  • 若是想使用, 能夠以 from xxx impoer _name 這種方式進行導入
相關文章
相關標籤/搜索