解決類與類之間代碼冗餘問題有兩種解決方案:python
一、繼承:描述的是類與類之間,什麼是什麼的關係linux
二、組合:描述的是類與類之間的關係,是一種什麼有什麼的關係函數
一個類產生的對象,該對象擁有一個屬性,這個屬性的值是來自於另一個類的對象ui
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將兩個類聯繫起來
什麼是封裝: 裝就是把一堆屬性存起來,封的概念就把這些屬性給隱藏起來,其實這種隱藏只是一種語法上的變形,對外不對內spa
注意:code
爲一個屬性名加__開頭
(注意不要加__結尾
),會在類定義階段將屬性名統一變形:_本身的類名__屬性名對象
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 明確地區份內外,對外是隱藏的,對內是開放的
這種語法意義上變形,只在類定義階段發生一次,類定義以後,新增的__開頭的屬性都沒有變形的效果blog
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
封裝數據屬性的目的:接口
把數據屬性封裝起來,而後須要開闢接口給類外部的使用者使用,好處是咱們能夠在接口之上添加控制邏輯,從而嚴格空間訪問者對屬性的操做
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()
用來將類內的函數假裝成一個數據屬性
例:
首先須要明確 : 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 # 報錯