繼承指的是類與類之間的關係,是一種什麼「是」什麼的關係,繼承的功能之一就是用來解決代碼重用問題python
繼承是一種建立新類的方式,在python中,新建的類能夠繼承一個或多個父類,父類又能夠成爲基類或超類,新建的類稱爲派生類或子類linux
固然子類也能夠添加本身新的屬性或者在本身這裏從新定義這些屬性(不會影響到父類),須要注意的是,一旦從新定義了本身的屬性且與父類重名,那麼調用新增的屬性時,就以本身爲準了。算法
class Hero: def __init__(self, nickname, life_value, aggressivity): self.nickname = nickname self.life_value = life_value self.aggressivity = aggressivity def attack(self, enemy): enemy.life_value -= self.aggressivity class Garen(Hero): camp = 'Demacia' class Riven(Hero): camp = 'Noxus' g = Garen('草叢倫', 100, 30)
在子類中,新建的重名的函數屬性,在編輯函數內功能的時候,有可能須要重用父類中重名的那個函數功能,應該是用調用普通函數的方式,即:類名.func(),此時就與調用普通函數無異了,所以即使是self參數也要爲其傳值app
1.只有在python2中才分新式類和經典類,python3中統一都是新式類 2.在python2中,沒有顯式的繼承object類的類,以及該類的子類,都是經典類 3.在python2中,顯式地聲明繼承object的類,以及該類的子類,都是新式類 4.在python3中,不管是否繼承object,都默認繼承object,即python3中全部類均爲新式類
python究竟是如何實現繼承的,對於你定義的每個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的全部基類的線性順序列表,例如函數
>>> F.mro() #等同於F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
爲了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類爲止。而這個MRO列表的構造是經過一個C3線性化算法來實現的。咱們不去深究這個算法的數學原理,它實際上就是合併全部父類的MRO列表並遵循以下三條準則:工具
在Java和C#中子類只能繼承一個父類,而Python中子類能夠同時繼承多個父類,若是繼承了多個父類,那麼屬性的查找方式有兩種,分別是:深度優先和廣度優先。spa
示範代碼3d
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__)
在子類派生出的新方法中,每每須要重用父類的方法,咱們有兩種方式實現code
方式一:指名道姓,即父類名.父類方法() 不依賴繼承 方式二:super() 依賴繼承blog
class Vehicle: # 定義交通工具類 Country = 'China' def __init__(self, name, speed, load, power): self.name = name self.speed = speed self.load = load self.power = power def run(self): print('開動啦...') class Subway(Vehicle): # 地鐵 def __init__(self, name, speed, load, power, line): Vehicle.__init__(self, name, speed, load, power) # 方式一:指名道姓 ''' python2: super(Subway, self).__init__(line) # 方式二:super(子類名, self).調用函數名(父類裏面的參數) python 3: super().__init__(line) # 可省略super括號裏的部分 即便沒有直接繼承關係,super仍然會按照mro繼續日後查找 ''' self.line = line def run(self): print('地鐵%s號線歡迎您' % self.line) Vehicle.run(self) line13 = Subway('中國地鐵', '180m/s', '1000人/箱', '電', 13) line13.run()
組合與繼承都是有效地利用已有類的資源的重要方式。可是兩者的概念和使用場景皆不一樣,
1.繼承的方式
經過繼承創建了派生類與基類之間的關係,它是一種'是'的關係,好比白馬是馬,人是動物。
當類之間有不少相同的功能,提取這些共同的功能作成基類,用繼承比較好,好比老師是人,學生是人
2.組合的方式
用組合的方式創建了類與組合的類之間的關係,它是一種‘有’的關係,好比教授有生日,教授教python和linux課程,教授有學生s一、s二、s3...
示例:繼承與組合
class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Course: def __init__(self,name,period,price): self.name=name self.period=period self.price=price def tell_info(self): print('<%s %s %s>' %(self.name,self.period,self.price)) class Teacher(People): def __init__(self,name,age,sex,job_title): People.__init__(self,name,age,sex) self.job_title=job_title self.course=[] self.students=[] class Student(People): def __init__(self,name,age,sex): People.__init__(self,name,age,sex) self.course=[] egon=Teacher('egon',18,'male','沙河霸道金牌講師') s1=Student('牛榴彈',18,'female') python=Course('python','3mons',3000.0) linux=Course('python','3mons',3000.0) #爲老師egon和學生s1添加課程 egon.course.append(python) egon.course.append(linux) s1.course.append(python) #爲老師egon添加學生s1 egon.students.append(s1) #使用 for obj in egon.course: obj.tell_info()
當類之間有顯著不一樣,而且較小的類是較大的類所須要的組件時,用組合比較好