1、什麼是繼承?
繼承指的是類別與類別之間的關係,是一種什麼是什麼的關係,功能之一就是用來解決程式碼重複使用問題。
繼承是一種建立新類別的方式,在python中,新建的類別可以繼承一個或多個父類,父類又可稱為基底類別或超類,新建的類別稱為派生類或子類,繼承又分為單繼承和多繼承。
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass print(Son1.__bases__) # 查看所有继承的父类 print(Son2.__bases__) =============== (<class '__main__.Father1'>,) (<class '__main__.Father1'>, <class '__main__.Father2'>)
2、繼承與抽象
抽象分成兩個層次:
1.將歐巴馬與梅西這兩個物件比較像的部分抽取成類別;
2.將人,豬,狗這三個類別比較像的部分抽取成父類別。
抽象最主要的作用是分割類別(可以隔離關注點,降低複雜度)
繼承:
#是基於抽象的結果,透過程式語言去實現它,肯定是先經歷抽象這個過程,才能透過繼承的方式去表達出抽象的結構。
抽像只是分析和設計的過程中,一個動作或是說一種技巧,透過抽象可以得到類別。
class animal(): # 定义父类 country = 'china' # 这个叫类的变量 def __init__(self,name,age): self.name=name # 这些又叫数据属性 self.age=age def walk(self): # 类的函数,方法,动态属性 print('%s is walking'%self.name) def say(self): pass class people(animal): # 子类继承父类 pass class pig(animal): # 子类继承父类 pass class dog(animal): # 子类继承父类 pass aobama=people('aobama',60) # 实例化一个对象 print(aobama.name) aobama.walk() =================== aobama aobama is walking
3、派生
1.在父類別的基礎上產生子類,產生的子類別就叫做派生類。 2.父類別裡沒有的方法,在子類別中有了,這樣的方法就叫做衍生方法。 3.父類別裡有,子類別也有的方法,就叫做方法的重寫(就是把父類別裡的方法重寫了)。 相關推薦:《Python影片教學
》範例1class Hero: def __init__(self, nickname, aggressivity, life_value): self.nickname = nickname self.aggressivity = aggressivity self.life_value = life_value def attack(self, enemy): enemy.life_value -= self.aggressivity class Garen(Hero): # 子类继承 hero 父类 camp='Demacia' # 子类衍生出的变量 def attack(self, enemy): # 跟父类的 attack 重名,对象调用的时候以子类的为准 pass def fire(self): # 父类没有 fire,这里 fire 属于派生出来的东西 print('%s is firing' %self.nickname) class Riven(Hero): camp='Noxus' g1=Garen('garen',18,200) r1=Riven('rivren',18,200) # print(g1.camp) # print(r1.camp) # g1.fire() g1.attack(g1)例2
class Hero: def __init__(self, nickname,aggressivity,life_value): self.nickname = nickname self.aggressivity = aggressivity self.life_value = life_value def attack(self, enemy): print('Hero attack') class Garen(Hero): camp = 'Demacia' def attack(self, enemy): #self=g1,enemy=r1 # self.attack(enemy) #g1.attack(r1),这里相当于无限递归 Hero.attack(self,enemy) # 引用 父类的 attack,对象会去跑 父类的 attack print('from garen attack') # 再回来这里 def fire(self): print('%s is firing' % self.nickname) class Riven(Hero): camp = 'Noxus' g1 = Garen('garen', 18, 200) r1 = Riven('rivren', 18, 200) g1.attack(r1) # print(g1.camp) # print(r1.camp) # g1.fire()
4、組合與重用性
重用性:方式1:不透過繼承的方式重複使用屬性,指名道姓的使用哪個類別的屬性。
class Hero: def __init__(self,nickname,gongji,life): self.nickname=nickname self.gongji=gongji self.life=life def attack(self,obj): print('from Hero attack') class Garen: def __init__(self,nickname,gongji,life,script): Hero.__init__(self,nickname,gongji,life) # 这里引用Hero类的 init,不用再自己从新定义一遍 init self.script=script # 父类 init 没有 script,这里是新加进来的属性 def attack(self,obj): # 在这里自己定义新的 attack,不再使用父类的 attack print('from Garen attack') def fire(self): # 在这里定义新的功能 print('from Garen fire') g1=Garen('garen',18,200,'人在塔在') print(g1.script) 人在塔在提示:用已經有的類別建立一個新的類,這樣就重用了已經有的軟體中的一部分甚至大部分,大大省了程式設計工作量,這就是常說的軟體重用,不僅可以重複使用自己的類,也可以繼承別人的,例如標準函式庫,來客製化新的資料類型,這樣就是大大縮短了軟體開發週期,對大型軟體開發來說,意義重大。 注意:像g1.life之類的屬性引用,會先從實例中找life,然後去類別中找,然後再去父類別中找...直到最頂級的父類別。 方式2:透過繼承範例1
class Hero(): def __init__(self, nickname, gongji, life): self.nickname = nickname self.gongji = gongji self.life = life def attack(self, obj): print('from Hero attack') obj.life -= self.gongji class Garen(Hero): # 使用 super方式需要继承 camp = 'Demacia' def __init__(self, nickname, gongji, life): super().__init__(nickname, gongji, life) def attack(self, obj): # 在这里自己定义新的 attack,不再使用父类的 attack super(Garen, self).attack(obj) # PY3中super可以不给参数,PY2中第一个参数必须是自己的类,self,可以使用 父类的方法,方法需要给参数就给参数 def fire(self): # 在这里定义新的功能 print('from Garen fire') g1 = Garen('garen1', 18, 200) g2 = Garen('garen2', 20, 100) print(g2.life) g1.attack(g2) print(g2.life) 100 from Hero attack 82範例2
class A: def f1(self): print('from A') super().f1() # 这种不需要继承也可以使用到 super,为什么,要看 C的 MRO表 class B: def f1(self): print('from B') class C(A,B): pass print(C.mro()) #[<class '__main__.C'>, # <class '__main__.A'>, # <class '__main__.B'>, # B在A的后面,当A指定 super().f1 会找到 B的 f1 # <class 'object'>] c=C() c.f1()
組合:
軟體重用的重要方式除了繼承之外還有另一種方式,即:組合。
組合:一個物件的資料屬性是另一個對象,稱為組合。class Equip: #武器装备类 def fire(self): print('release Fire skill') class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类 camp='Noxus' def __init__(self,nickname): self.nickname=nickname self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性 r1=Riven('锐雯雯') r1.equip.fire() #可以使用组合的类产生的对象所持有的方法 release Fire skill
組合的方式:
組合與繼承都是有效地利用已有類別的資源的重要方式。但二者的概念和使用場景皆不同。 1.繼承的方式透過繼承建立了衍生類別與基底類別之間的關係,它是一種'是'的關係,例如白馬是馬,人是動物。 當類別之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如老師是人,學生是人2.組合的方式用組合的方式建立了類與組合的類之間的關係,它是一種'有'的關係,比如教授有生日,教授教python和linux課程,教授有學生s1、s2 、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()
5、介面與歸一化設計
a、為何要用介面?
介面提取了一群類別共同的函數,可以把介面當作一個函數的集合。 然後讓子類別去實作介面中的函數。這麼做的意義在於歸一化,什麼叫歸一化,就是只要是基於同一個介面實現的類,那麼所有的這些類產生的物件在使用時,從用法上來說都一樣。
歸一化的好處在於:歸一化讓使用者不需要關心物件的類別是什麼,只需要的知道這些物件都具備某些功能就可以了,這極大地降低了使用者的使用難度。 ###class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。 def read(self): #定接口函数read pass def write(self): #定义接口函数write pass class Txt(Interface): #文本,具体实现read和write def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(Interface): #磁盘,具体实现read和write def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(Interface): def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法')###上面的程式碼只是看起來像接口,其實並沒有起到接口的作用,子類別完全可以不用去實現接口,這就用到了抽象類別。 #########6、抽象類別#########子類別必須繼承抽象類別的方法,不然報錯。 #########什麼是抽象類別? #########與java一樣,python也有抽象類別的概念但是同樣需要藉助模組實現,抽象類別是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化# ########為什麼要有抽象類別? #########如果說類別是從一堆物件中抽取相同的內容而來的,那麼抽象類別就是從一堆類別中抽取相同的內容而來的,內容包括資料屬性和函數屬性。 ###
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。
抽象类与接口
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。
例1
import abc #抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们 class Animal(metaclass=abc.ABCMeta): # 抽象类是用来被子类继承的,不是用来实例化的 tag='123123123123123' @abc.abstractmethod # 如果子类没有我这个函数,主动抛出异常 def run(self): pass @abc.abstractmethod def speak(self): pass class People(Animal): def run(self): # 子类必须有抽象类里的装饰器下面的函数 pass def speak(self): pass peo1=People() # 实例化出来一个人 print(peo1.tag)
例2
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' #一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' @abc.abstractmethod #定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' pass @abc.abstractmethod #定义抽象方法,无需实现功能 def write(self): '子类必须定义写功能' pass # class Txt(All_file): # pass # # t1=Txt() #报错,子类没有定义抽象方法 class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法') wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.read() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type)
以上是一文了解什麼是Python物件導向中的繼承的詳細內容。更多資訊請關注PHP中文網其他相關文章!