类的继承实例
類的繼承實例
繼承
面向?qū)ο缶幊?(OOP) 語言的一個主要功能就是“繼承”。繼承是指這樣一種能力:它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展。
通過繼承創(chuàng)建的新類稱為“子類”或“派生類”。
被繼承的類稱為“基類”、“父類”或“超類”。
繼承的過程,就是從一般到特殊的過程。
要實現(xiàn)繼承,可以通過“繼承”(Inheritance)和“組合”(Composition)來實現(xiàn)。
在某些 OOP 語言中,一個子類可以繼承多個基類。但是一般情況下,一個子類只能有一個基類,要實現(xiàn)多重繼承,可以通過多級繼承來實現(xiàn)。
繼承概念的實現(xiàn)方式主要有2類:實現(xiàn)繼承、接口繼承。
??????????實現(xiàn)繼承是指使用基類的屬性和方法而無需額外編碼的能力; ??????????接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現(xiàn)的能力(子類重構(gòu)爹類方法); 在考慮使用繼承時,有一點需要注意,那就是兩個類之間的關(guān)系應(yīng)該是“屬于”關(guān)系。例如,Employee 是一個人,Manager 也是一個人,因此這兩個類都可以繼承 Person 類。但是 Leg 類卻不能繼承 Person 類,因為腿并不是一個人。 抽象類僅定義將由子類創(chuàng)建的一般屬性和方法。OO開發(fā)范式大致為:劃分對象→抽象類→將類組織成為層次化結(jié)構(gòu)(繼承和合成) →用類與實例進行設(shè)計和實現(xiàn)幾個階段。
下面我們來看個繼承的簡單實例:
如果子類有一個跟父類一樣的方法:
我們現(xiàn)在給父類增加兩個參數(shù),name,age。
這個時候調(diào)用子類用方法b=BlackPerson(),必須帶上參數(shù)name和age,否則就會報錯。如下圖:
子類調(diào)用必須加上參數(shù)如下圖:
如果我想給子類傳參數(shù),不可以在子類下面增加初始化函數(shù)。
我們應(yīng)該先繼承再重構(gòu)函數(shù):
甚至在子類里可以自定義新的屬性了,如下圖:
?現(xiàn)在我們來看一個完整的學(xué)校,老師和學(xué)生的例子:
class SchoolMember(object):'''學(xué)校成員基類'''member = 0def __init__(self,name,age,sex):self.name = nameself.age = ageself.sex = sexself.enroll()def enroll(self):'''注冊'''print("just enrolled a new school member [%s]"% self.name)SchoolMember.member +=1def tell(self):print("------info:%s-----"%self.name)for k,v in self.__dict__.items():print("\t",k,v)print("------end-----")def __del__(self):print("開除了[%s]..."% self.name )SchoolMember.member -=1class School(object):'''學(xué)校類'''def open_branch(self,addr):print("openning a new branch in ",addr)class Teacher(SchoolMember,School):'''講師類'''def __init__(self,name,age,sex,salary,course):#SchoolMember.__init__(self,name,age,sex) #經(jīng)典類寫法super(Teacher,self).__init__(name,age,sex) #新式類寫法self.salary = salaryself.course = course# def tell(self):# print("""--------info:%s# name:%s# age:%s# salary :%s# """ % (self.name,self.name,self.age,self.salary))def teaching(self):print("Teacher [%s] is teaching [%s]" % (self.name,self.course))class Student(SchoolMember):def __init__(self,name,age,sex,course,tuition):SchoolMember.__init__(self,name,age,sex)self.course = courseself.tuition = tuition #feeself.amount = 0def pay_tuition(self,amount):print("student [%s] has just paied [%s]" %(self.name,amount))self.amount += amountt1 = Teacher("Wusir", 28, "F*M",3000,"Python" ) s1 = Student("HaiTao", 38,"N/A","PYS15", 300000 ) s2 = Student("LIChuang",12,"M","PYS15", 11000 )print(SchoolMember.member) t1.tell() t1.open_branch("SH") s2.tell() del s2print(SchoolMember.member)上面的例子,幾個注意要點:
這必須用類名SchoolMember而不能用self,如果用self就沒法實現(xiàn)全局變量進行累加的效果了~!
我們?nèi)绻氪蛴±蠋熀蛯W(xué)生,實例的所有信息,怎么便捷的操作呢?
我們發(fā)現(xiàn)實例后面.__dict__可以用字典的方式把所有的信息打印出來:
那么我們可以在父類直接加上循環(huán)打印實例信息。
在上面代碼里,還有一個多繼承的問題,也就是老師其實繼承了2個父類,一個SchoolMember一個是School。
最后我們來看下繼承父類有兩個寫法,新式類VS經(jīng)典類:
其實新式類的定義class Person(object),這個object也是一個系統(tǒng)默認的類,那么為什么python要讓所有的類的父類都是object呢?
因為萬一以后python想給類class加什么新功能,它直接加在class object的方法就可以,這樣就可以無限擴展了!所以推薦用新式類的寫法來給類定義。
現(xiàn)在我們再來看一個在經(jīng)典模式和新式模式下,構(gòu)建函數(shù),初始化的查找順序問題:
在默認的情況下,見下面的代碼:
class A(object):def __init__(self):self.n = "A" class B(A):# passdef __init__(self):self.n = "B" class C(A):#passdef __init__(self):self.n = "C" class D(B,C):# passdef __init__(self):self.n = "D" d = D() print(d.n)打印出來的結(jié)果肯定是D,這個時候搜索的最近的初始化。
如果我們把D的初始化注釋掉:
這個時候打印出來的結(jié)果是B;
同樣我們把B注釋掉,打印出來的是C;
再把C注釋掉,打印出來的是A。
我們來看下面的關(guān)系圖:
查找的順序是D->B->C->A,也就是在PY3里,查找的順序是按廣度查詢的方式,先在同級的class查找,然后再按深度查詢的方法,查找到A。
同樣在經(jīng)典模式的情況下,也就是把A的object去掉:
這個時候在PY3里查找的順序依舊是D->B->C->A。
但是注意,有特殊的情況,如果在PY2里,經(jīng)典模式的查找順序就是D->B->A->C,在PY2里查找的順序優(yōu)先是深度查找,然后才是廣度查詢!
?
總結(jié)
- 上一篇: mysql数据库从删库到跑路之mysql
- 下一篇: php加密技术