7.4 組合 解決類與類之間代碼冗餘問題有兩種解決方案: 1、繼承:描述的是類與類之間,什麼是什麼的關係 2、組合:描述的是類與類之間的關係,是一種什麼有什麼的關係 一個類產生的對象,該對象擁有一個屬性,這個屬性的值是來自於另外一個類的對象 7.5 封裝 什麼是封裝: 裝就是把一堆屬性存起來,封的概 ...
7.4 組合
解決類與類之間代碼冗餘問題有兩種解決方案:
1、繼承:描述的是類與類之間,什麼是什麼的關係
2、組合:描述的是類與類之間的關係,是一種什麼有什麼的關係
一個類產生的對象,該對象擁有一個屬性,這個屬性的值是來自於另外一個類的對象
class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print('出生年月日<%s-%s-%s>' % (self.year, self.mon, self.day)) class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): super().__init__(name,age,sex) #重用父類功能 self.level=level self.salary=salary def change_score(self): print('teacher %s is changing score' %self.name) class Oldboystudent(OldboyPeople): def __init__(self,name,age,sex,course,): super().__init__(name,age,sex,) #重用父類功能 self.course=course def choose(self): print('student %s choose course' %self.name) tea1=OldboyTeacher('egon',18,'male',9,3.1) #創建老師類的對象tea1 date_obj=Date(2000,1,1) #創建Date類的對象date_obj date_obj.tell_birth() #date_obj可以調用綁定方法tell_birth tea1.birth=date_obj #tea1的birth屬性來自於Date類的一個對象date_obj tea1.birth.tell_birth() #tea1的birth屬性可以調用tell_birth屬性 stu1=Oldboystudent('張三',16,'male','linux') stu1.birth=Date(2002,3,3) stu1.birth.tell_birth() stu1.choose() #使用stu1將兩個類聯繫起來View Code
7.5 封裝
什麼是封裝: 裝就是把一堆屬性存起來,封的概念就把這些屬性給隱藏起來,其實這種隱藏只是一種語法上的變形,對外不對內
註意:
為一個屬性名加__開頭
(註意不要加__結尾
),會在類定義階段將屬性名統一變形:_自己的類名__屬性名
class Foo: x=1 __x=1111 #_Foo__x=1111 def __init__(self,y): self.__y=y #self._Foo__y=y def __f1(self): #_Foo__f1 print('Foo.f1') def get_y(self): print(self.__y) # print(self._Foo__y) obj=Foo(22222) print(obj.x) # 1 print(obj.__x) # 報錯 print(obj._Foo__x) # 1111 obj.__f1() #報錯 obj._Foo__f1() # Foo.f1 print(obj.y) #報錯 print(obj.__y) #報錯 print(obj._Foo__y) # 22222 obj.get_y() # 22222 明確地區分內外,對外是隱藏的,對內是開放的
這種語法意義上變形,只在類定義階段發生一次,類定義之後,新增的__開頭的屬性都沒有變形的效果
Foo.__aaa=1
print(obj.__aaa) # 1
如果父類不想讓子類覆蓋自己的方法,可以在方法名前加__開頭
class Foo: def __f1(self): #_Foo__f1 print('Foo.f1') def f2(self): print('Foo.f2') self.__f1() #obj._Foo__f1() class Bar(Foo): def __f1(self): #_Bar__f1 print("Bar.f1") obj=Bar() obj.f2() # Foo.f2 Foo.f1
7.51 封裝的作用
封裝數據屬性的目的:
把數據屬性封裝起來,然後需要開闢介面給類外部的使用者使用,好處是我們可以在介面之上添加控制邏輯,從而嚴格空間訪問者對屬性的操作
class People: def __init__(self,name): self.__name=name def tell_name(self): # 添加邏輯 return self.__name obj=People('egon') #obj.__name obj.tell_name()
封裝函數屬性的目的:為了隔離複雜度
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() obj=ATM() obj.withdraw()
7.52 封裝之property
用來將類內的函數偽裝成一個數據屬性
例:
體質指數()體重()身高()首先需要明確 : bmi是算出來的,不是一個固定死的值,也就說我們必須編寫一個功能,每次調用該功能 都會立即計算一個值
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property #於是我們需要為bmi這個函數添加裝飾器,將其偽裝成一個數據屬性 def bmi(self): return self.weight / (self.height * self.height) egon=People('egon',75,1.80) yl=People('yangli',85,1.74) # print(egon.bmi()) # print(yl.bmi()) print(egon.bmi) # 21.604938271604937,調用egon.bmi本質就是觸發函數bmi的執行,從而拿到其返回值 print(yl.bmi) # 把功能偽裝成一個屬性
@name.setter 和 @name.deleter
# egon.bmi=123 # egon.bmi背後對應的是一個函數,所以不能賦值 class People: def __init__(self,name): self.__name=name @property def name(self): # 添加邏輯 return self.__name @name.setter def name(self,x): # 添加邏輯 self.__name=x @name.deleter def name(self): # 添加邏輯 del self.__name obj=People('egon') print(obj.name) # egon # 修改 obj.name='EGON' # 現在可以賦值 print(obj.name) # EGON del obj.name # 刪除 obj.name # 報錯