<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 隱藏 從封裝本身的意思去理解,封裝就好像是拿來一個麻袋,把小貓,小狗,小王八一起裝進麻袋,然后把麻袋封上口子。照這種邏輯看,封裝=‘隱藏’ ### 如何隱藏屬性 在python中用雙下劃線開頭的方式將屬性隱藏起來(設置成私有的) ~~~ #其實這僅僅這是一種變形操作 #類中所有雙下劃線開頭的名稱如__x都會自動變形成:_類名__x的形式: class A: __N=0 #變形為_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的形式訪問到. #A._A__N是可以訪問到的,即這種操作并不是嚴格意義上的限制外部訪問,僅僅只是一種語法意義上的變形 ~~~ ### **自動變形的特點:** 1. 類中定義的\_\_x只能在內部使用,如self.\_\_x,引用的就是變形的結果。 2. 這種變形其實正是針對外部的變形,在外部是無法通過\_\_x這個名字訪問到的。 3. 在子類定義的\_\_x不會覆蓋在父類定義的\_\_x, 因為子類中變形成了:\_子類名\_\_x,而父類中變形成了:\_父類名\_\_x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。 ### **變形需要注意的問題:** 1. 并沒有真正意義上限制從外部直接訪問屬性 知道了類名和屬性名就可以拼出名字:\_類名\_\_屬性,然后就可以訪問了,如a.\_A\_\_N 2. 變形的過程只在類的定義是發生一次,在定義后的賦值操作,不會變形 3. 在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的 ~~~ #把fa定義成私有的,即__fa >>> class A: ... def __fa(self): #在定義時就變形為_A__fa ... print('from A') ... def test(self): ... self.__fa() #只會與自己所在的類為準,即調用_A__fa ... >>> class B(A): ... def __fa(self): ... print('from B') ... >>> b=B() >>> b.test() from A ~~~ ## 封裝 ### 1.封裝數據 將數據隱藏起來這不是目的。隱藏起來然后對外提供操作該數據的接口,然后我們可以在接口附加上對該數據操作的限制,以此完成對數據屬性操作的嚴格控制。 ~~~ class Teacher: def __init__(self,name,age): self.__name=name self.__age=age def tell_info(self): print('姓名:%s,年齡:%s' %(self.__name,self.__age)) def set_info(self,name,age): if not isinstance(name,str): raise TypeError('姓名必須是字符串類型') if not isinstance(age,int): raise TypeError('年齡必須是整型') self.__name=name self.__age=age t=Teacher('egon',18) t.tell_info() t.set_info('egon',19) t.tell_info() ~~~ ### 2.封裝方法 目的是隔離復雜度,舉例如下 取款是功能,而這個功能有很多功能組成:插卡、密碼認證、輸入金額、打印賬單、取錢 對使用者來說,只需要知道取款這個功能即可,其余功能我們都可以隱藏起來,這么做隔離了復雜度,同時也提升了安全性 ~~~ class ATM: def __card(self): print('插卡') def __auth(self): print('用戶認證') def __input(self): print('輸入取款金額') def __print_bill(self): print('打印賬單') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw() ~~~ 提示:在編程語言里,對外提供的接口(接口可理解為了一個入口),可以是函數,稱為接口函數,這與接口的概念還不一樣,接口代表一組接口函數的集合體。 ## 特性(property) 將函數屬性偽裝得像數據屬性一樣被用戶訪問,即訪問函數不需要括號 ### **什么是特性property** property是一種特殊的屬性,訪問它時會執行一段功能(函數)然后返回值,可以將一個方法作為屬性對外展示. 案例:圓的周長和面積 ~~~ import math class Circle: def __init__(self,radius): #圓的半徑radius self.radius=radius @property def area(self): return math.pi * self.radius**2 #計算面積 @property def perimeter(self): return 2*math.pi*self.radius #計算周長 c=Circle(10) print(c.radius) print(c.area) #可以向訪問數據屬性一樣去訪問area,會觸發一個函數的執行,動態計算出一個值 print(c.perimeter) #注意沒有使用c.perimeter()而是使用的c.perimeter 輸出結果: 314.1592653589793 62.83185307179586 ~~~ 注意:此時的特性area和perimeter不能被賦值 ~~~ c.area=3 #為特性area賦值 ''' 拋出異常: AttributeError: can't set attribute ''' ~~~ ### **為什么要用property** 將一個類的函數定義成特性以后,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然后計算出來的,這種特性的使用方式**遵循了統一訪問的原則** ### 面向對象的三種封裝方式 1. 【public】 這種其實就是不封裝,是對外公開的 2. 【protected】 這種封裝方式對外不公開,但對朋友(friend)或者子類公開 3. 【private】 這種封裝對誰都不公開 ### pyton中的實現 python并沒有在語法上把它們三個內建到自己的class機制中,在C++里一般會將所有的所有的數據都設置為私有的,然后提供set和get方法(接口)去設置和獲取,在python中通過property方法可以實現 ~~~ class Foo: def __init__(self,val): self.__NAME=val #將所有的數據屬性都隱藏起來 @property def name(self): return self.__NAME #obj.name訪問的是self.__NAME @name.setter #提供設置方法,使用過property裝飾過的函數才有此方法 def name(self,value): if not isinstance(value,str): #在設定值之前進行類型檢查 raise TypeError('%s must be str' %value) self.__NAME=value #通過類型檢查后,將值value存放到真實的位置self.__NAME @name.deleter #提供刪除方法 def name(self): raise TypeError('Can not delete') f=Foo('egon') print(f.name) # f.name=10 #拋出異常'TypeError: 10 must be str' del f.name #拋出異常'TypeError: Can not delete' ~~~ ## 封裝與擴展性 封裝在于明確區分內外,使得類實現者可以修改封裝內的東西而不影響外部調用者的代碼;而外部使用用者只知道一個接口(函數),只要接口(函數)名、參數不變,使用者的代碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要接口這個基礎約定不變,則代碼改變不足為慮。 ~~~ #類的設計者 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #對外提供的接口,隱藏了內部的實現細節,此時我們想求的是面積 return self.__width * self.__length #使用者 >>> r1=Room('臥室','egon',20,20,20) >>> r1.tell_area() #使用者調用接口tell_area #類的設計者,輕松的擴展了功能,而類的使用者完全不需要改變自己的代碼 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): return self.__width * self.__length * self.__high ''' 對外提供的接口,隱藏內部實現,此時我們想求的是體積,內部邏輯變了, 只需修該一行就可以很簡答的實現,而且外部調用感知不到, 仍然使用該方法,但是功能已經變了''' #對于仍然在使用tell_area接口的人來說,根本無需改動自己的代碼,就可以用上新功能 >>> r1.tell_area() ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看