Python 面向對象三大特征之封裝

      網友投稿 726 2022-05-30

      封裝

      【封裝】

      隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。

      【好處】

      1. 將變化隔離;

      2. 便于使用;

      3. 提高復用性;

      4. 提高安全性;

      【封裝原則】

      Python 面向對象三大特征之封裝

      1. 將不需要對外提供的內容都隱藏起來;

      2. 把屬性都隱藏,提供公共方法對其訪問。

      1、私有變量和私有方法

      在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的形式訪問到. #A._A__N是可以訪問到的,即這種操作并不是嚴格意義上的限制外部訪問,僅僅只是一種語法意義上的變形

      這種自動變形的特點:

      1.類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。

      2.這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字訪問到的。

      3.在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。

      這種變形需要注意的問題是:

      1.這種機制也并沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然后就可以訪問了,如a._A__N

      2.變形的過程只在類的內部生效,在定義后的賦值操作,不會變形

      3.在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的

      #正常情況 >>>?class?A: ...?????def?fa(self): ...?????????print('from?A') ...?????def?test(self): ...?????????self.fa() ...? >>>?class?B(A): ...?????def?fa(self): ...?????????print('from?B') ...? >>>?b=B() >>>?b.test() from?B ? #把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

      2、封裝與擴展性

      封裝在于明確區分內外,使得類實現者可以修改封裝內的東西而不影響外部調用者的代碼;而外部使用用者只知道一個接口(函數),只要接口(函數)名、參數不變,使用者的代碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要接口這個基礎約定不變,則代碼改變不足為慮。

      #類的設計者 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()

      3、property屬性

      什么是特性property

      property是一種特殊的屬性,訪問它時會執行一段功能(函數)然后返回值

      例一:BMI指數(bmi是計算而來的,但很明顯它聽起來像是一個屬性而非方法,如果我們將其做成一個屬性,更便于理解) 成人的BMI數值: 過輕:低于18.5 正常:18.5-23.9 過重:24-27 肥胖:28-32 非常肥胖,?高于32   體質指數(BMI)=體重(kg)÷身高^2(m)   EX:70kg÷(1.75×1.75)=22.86

      class?People: ????def?__init__(self,name,weight,height): ????????self.name=name ????????self.weight=weight ????????self.height=height ????@property ????def?bmi(self): ????????return?self.weight?/?(self.height**2) p1=People('egon',75,1.85) print(p1.bmi)

      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)?#同上 ''' 輸出結果: 314.1592653589793 62.83185307179586 '''

      #注意:此時的特性area和perimeter不能被賦值 c.area=3?#為特性area賦值 ''' 拋出異常: AttributeError:?can't?set?attribute '''

      為什么要用property

      將一個類的函數定義成特性以后,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然后計算出來的,這種特性的使用方式遵循了統一訪問的原則

      除此之外,看下

      ps:面向對象的封裝有三種方式: 【public】 這種其實就是不封裝,是對外公開的 【protected】 這種封裝方式對外不公開,但對朋友(friend)或者子類(形象的說法是“兒子”,但我不知道為什么大家?不說“女兒”,就像“parent”本來是“父母”的意思,但中文都是叫“父類”)公開 【private】 這種封裝對誰都不公開

      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 ????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'

      一個靜態屬性property本質就是實現了get,set,delete三種方法

      class?Foo: ????@property ????def?AAA(self): ????????print('get的時候運行我啊') ????@AAA.setter ????def?AAA(self,value): ????????print('set的時候運行我啊') ????@AAA.deleter ????def?AAA(self): ????????print('delete的時候運行我啊') #只有在屬性AAA定義property后才能定義AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del?f1.AAA

      class?Foo: ????def?get_AAA(self): ????????print('get的時候運行我啊') ????def?set_AAA(self,value): ????????print('set的時候運行我啊') ????def?delete_AAA(self): ????????print('delete的時候運行我啊') ????AAA=property(get_AAA,set_AAA,delete_AAA)?#內置property三個參數與get,set,delete一一對應 f1=Foo() f1.AAA f1.AAA='aaa' del?f1.AAA

      怎么用?

      class?Goods: ????def?__init__(self): ????????#?原價 ????????self.original_price?=?100 ????????#?折扣 ????????self.discount?=?0.8 ????@property ????def?price(self): ????????#?實際價格?=?原價?*?折扣 ????????new_price?=?self.original_price?*?self.discount ????????return?new_price ????@price.setter ????def?price(self,?value): ????????self.original_price?=?value ????@price.deleter ????def?price(self): ????????del?self.original_price obj?=?Goods() obj.price?????????#?獲取商品價格 obj.price?=?200???#?修改商品原價 print(obj.price) del?obj.price?????#?刪除商品原價

      4、classmethod

      class?Classmethod_Demo(): ????role?=?'dog' ????@classmethod ????def?func(cls): ????????print(cls.role) Classmethod_Demo.func()

      5、staticmethod

      class?Staticmethod_Demo(): ????role?=?'dog' ????@staticmethod ????def?func(): ????????print("當普通方法用") Staticmethod_Demo.func()

      練習1:

      class?Foo: ????def?func(self): ????????print('in?father') class?Son(Foo): ????def?func(self): ????????print('in?son') s?=?Son() s.func() #?請說出上面一段代碼的輸出并解釋原因?

      練習2:

      class?A: ????__role?=?'CHINA' ????@classmethod ????def?show_role(cls): ????????print(cls.__role) ????@staticmethod ????def?get_role(): ????????return?A.__role ????@property ????def?role(self): ????????return?self.__role a?=?A() print(a.role) print(a.get_role()) a.show_role() #?__role在類中有哪些身份? #?以上代碼分別輸出哪些內容? #?這三個裝飾器分別起了什么作用?有哪些區別?

      軟件開發 人工智能 云計算 機器學習

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:與全球開發者共成長,共贏計算新時代
      下一篇:打造終身教育體系,讓學習不再有邊界!
      相關文章
      亚洲丶国产丶欧美一区二区三区 | JLZZJLZZ亚洲乱熟无码| 国产成人亚洲综合网站不卡| 亚洲国产精品热久久| 亚洲中文字幕在线第六区| 亚洲午夜福利精品久久| 亚洲人成无码www久久久| 亚洲福利精品一区二区三区| 亚洲avav天堂av在线网毛片| 亚洲精品动漫免费二区| 亚洲人成色77777在线观看| 亚洲精品中文字幕| 亚洲Av永久无码精品黑人| 国产亚洲午夜精品| 亚洲高清免费视频| 亚洲天堂免费在线视频| 亚洲一区二区三区无码中文字幕| 亚洲中文字幕无码一区二区三区| 亚洲日韩精品无码专区网址 | 亚洲成?Ⅴ人在线观看无码| 亚洲区小说区图片区| 亚洲色精品vr一区二区三区 | 亚洲avav天堂av在线不卡| 久久久久久久亚洲Av无码| 亚洲高清资源在线观看| 亚洲国产成AV人天堂无码| 日本亚洲免费无线码| 午夜亚洲WWW湿好爽| 亚洲精品97久久中文字幕无码| 中文字幕亚洲第一| 亚洲国产精品无码AAA片| 久久亚洲日韩精品一区二区三区| 亚洲欧洲日产国码www| 亚洲日韩国产精品乱-久| 欧美亚洲国产SUV| 亚洲日本va午夜中文字幕久久| 亚洲人成无码网站| 亚洲黄色免费在线观看| 亚洲jizzjizz在线播放久| 亚洲AV成人精品日韩一区| 色久悠悠婷婷综合在线亚洲|