python面向對象之 封裝(Day25)
阿新 • • 發佈:2017-08-15
imp disco font 使用 ati 所有 下劃線 error: 無法
封裝:
隱藏對象的屬性和實現細節,僅對外提供公共訪問方式
好處:1.將變化隔離
2.便於使用
3.提高復用性
4.提高安全性
封裝原則:
1.將不需要對外提供的內容隱藏起來
2.把屬性都隱藏,提供公共方法對其訪問
二.私有變量和私有方法
在Python中用雙下劃線開頭的方式將屬性隱藏起來(設置成私有的)
2.1 私有變量
#其實這僅僅這是一種變形操作 #類中所有雙下劃線開頭的名稱如__x都會自動變形成:_類名__x的形式: class A: __N=0 #類的數據屬性就應該是共享的,但是語法上是可以把類的數據屬性設置成私有的如__N,會變形為_A__Ndef __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,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
2.2 私有方法
在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有
#正常情況 >>> class A: ... def fa(self): ... print(‘from A‘) ... def test(self): ... self.fa() ... >>> classB(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
三.封裝與擴展性
封裝在於明確區分內外,使得類實現者可以修改封裝內的東西而不影響外部調用者的代碼;而外部使用用者只知道一個接口(函數),只要接口(函數)名、參數不變,使用者的代碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要接口這個基礎約定不變,則代碼改變不足為慮。
#類的設計者 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()View Code
四.property屬性
1. 什麽是property呢?
property是一種特殊的屬性,訪問他時會執行一段功能 (函數)然後返回值
#@property把一個類中的方法 偽裝成屬性 #obj.func() #obj.func -->屬性 #因為屬性不能被修改 #@funcname.setter #obj.func = new_value [email protected] #[email protected]@funcname.setter裝飾的方法同名 #@funcname.deleter #在執行del obj.func 的時候會調用被這個裝飾器裝飾的方法(同名)
例一: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 ‘‘‘
2. 超市打折實例:
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 # 刪除商品原價
classmethod
class Classmethod_Demo(): role = ‘dog‘ @classmethod def func(cls): print(cls.role) c = Classmethod_Demo() c.func()
staticmethod
class Staticmethod_Demo(): role = ‘dog‘ @staticmethod def func(): print("當普通方法用") c = Staticmethod_Demo() c.func()
python面向對象之 封裝(Day25)