首頁 >後端開發 >Python教學 >一文了解什麼是Python物件導向中的繼承

一文了解什麼是Python物件導向中的繼承

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼轉載
2019-08-28 17:40:023012瀏覽

一文了解什麼是Python物件導向中的繼承

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 &#39;__main__.Father1&#39;>,)
(<class &#39;__main__.Father1&#39;>, <class &#39;__main__.Father2&#39;>)

2、繼承與抽象

抽象分成兩個層次:

1.將歐巴馬與梅西這兩個物件比較像的部分抽取成類別;

2.將人,豬,狗這三個類別比較像的部分抽取成父類別。

抽象最主要的作用是分割類別(可以隔離關注點,降低複雜度)

一文了解什麼是Python物件導向中的繼承

繼承:

一文了解什麼是Python物件導向中的繼承

#是基於抽象的結果,透過程式語言去實現它,肯定是先經歷抽象這個過程,才能透過繼承的方式去表達出抽象的結構。

抽像只是分析和設計的過程中,一個動作或是說一種技巧,透過抽象可以得到類別。

class animal():   # 定义父类
    country  =  &#39;china&#39;     # 这个叫类的变量
    def __init__(self,name,age):
        self.name=name   # 这些又叫数据属性
        self.age=age
    def walk(self):         # 类的函数,方法,动态属性
        print(&#39;%s is walking&#39;%self.name)
    def say(self):
        pass
class people(animal):  # 子类继承父类
    pass
class pig(animal):    # 子类继承父类
    pass
class dog(animal):  # 子类继承父类
    pass
aobama=people(&#39;aobama&#39;,60)   # 实例化一个对象
print(aobama.name)
aobama.walk()
===================
aobama
aobama is walking

3、派生

1.在父類別的基礎上產生子類,產生的子類別就叫做派生類。

2.父類別裡沒有的方法,在子類別中有了,這樣的方法就叫做衍生方法。

3.父類別裡有,子類別也有的方法,就叫做方法的重寫(就是把父類別裡的方法重寫了)。

相關推薦:《

Python影片教學

範例1

class 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=&#39;Demacia&#39;   # 子类衍生出的变量
    def attack(self, enemy):   # 跟父类的 attack 重名,对象调用的时候以子类的为准
        pass
    def fire(self):    # 父类没有 fire,这里 fire 属于派生出来的东西
        print(&#39;%s is firing&#39; %self.nickname)
class Riven(Hero):
    camp=&#39;Noxus&#39;
g1=Garen(&#39;garen&#39;,18,200)
r1=Riven(&#39;rivren&#39;,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(&#39;Hero attack&#39;)
class Garen(Hero):
    camp = &#39;Demacia&#39;
    def attack(self, enemy): #self=g1,enemy=r1
        # self.attack(enemy) #g1.attack(r1),这里相当于无限递归
        Hero.attack(self,enemy)  # 引用 父类的 attack,对象会去跑 父类的 attack
        print(&#39;from garen attack&#39;)  # 再回来这里
    def fire(self):
        print(&#39;%s is firing&#39; % self.nickname)
class Riven(Hero):
    camp = &#39;Noxus&#39;
g1 = Garen(&#39;garen&#39;, 18, 200)
r1 = Riven(&#39;rivren&#39;, 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(&#39;from Hero attack&#39;)
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(&#39;from Garen attack&#39;)
    def fire(self):  # 在这里定义新的功能
        print(&#39;from Garen fire&#39;)
g1=Garen(&#39;garen&#39;,18,200,&#39;人在塔在&#39;)
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(&#39;from Hero attack&#39;)
        obj.life -= self.gongji
class Garen(Hero):   # 使用 super方式需要继承
    camp = &#39;Demacia&#39;
    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(&#39;from Garen fire&#39;)
g1 = Garen(&#39;garen1&#39;, 18, 200)
g2 = Garen(&#39;garen2&#39;, 20, 100)
print(g2.life)
g1.attack(g2)
print(g2.life)
100
from Hero attack
82

範例2

class A:
    def f1(self):
        print(&#39;from A&#39;)
        super().f1()    
        # 这种不需要继承也可以使用到 super,为什么,要看 C的 MRO表
class B:
    def f1(self):
        print(&#39;from B&#39;)
class C(A,B):
    pass
print(C.mro())
#[<class &#39;__main__.C&#39;>,
# <class &#39;__main__.A&#39;>,
# <class &#39;__main__.B&#39;>, #  B在A的后面,当A指定 super().f1 会找到 B的 f1
# <class &#39;object&#39;>]
c=C()
c.f1()

組合:

軟體重用的重要方式除了繼承之外還有另一種方式,即:組合。

組合:一個物件的資料屬性是另一個對象,稱為組合。

class Equip: #武器装备类
    def fire(self):
        print(&#39;release Fire skill&#39;)
class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
    camp=&#39;Noxus&#39;
    def __init__(self,nickname):
        self.nickname=nickname
        self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
r1=Riven(&#39;锐雯雯&#39;)
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(&#39;<%s %s %s>&#39; %(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(&#39;egon&#39;,18,&#39;male&#39;,&#39;沙河霸道金牌讲师&#39;)
s1=Student(&#39;牛榴弹&#39;,18,&#39;female&#39;)
python=Course(&#39;python&#39;,&#39;3mons&#39;,3000.0)
linux=Course(&#39;python&#39;,&#39;3mons&#39;,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(&#39;文本数据的读取方法&#39;)
    def write(self):
        print(&#39;文本数据的读取方法&#39;)
class Sata(Interface): #磁盘,具体实现read和write
    def read(self):
        print(&#39;硬盘数据的读取方法&#39;)
    def write(self):
        print(&#39;硬盘数据的读取方法&#39;)
class Process(Interface):
    def read(self):
        print(&#39;进程数据的读取方法&#39;)
    def write(self):
        print(&#39;进程数据的读取方法&#39;)
###上面的程式碼只是看起來像接口,其實並沒有起到接口的作用,子類別完全可以不用去實現接口,這就用到了抽象類別。 #########6、抽象類別#########子類別必須繼承抽象類別的方法,不然報錯。 #########什麼是抽象類別? #########與java一樣,python也有抽象類別的概念但是同樣需要藉助模組實現,抽象類別是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化# ########為什麼要有抽象類別? #########如果說類別是從一堆物件中抽取相同的內容而來的,那麼抽象類別就是從一堆類別中抽取相同的內容而來的,內容包括資料屬性和函數屬性。 ###

比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。你永远无法吃到一个叫做水果的东西。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。

抽象类与接口

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。

例1

import abc
#抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们
class Animal(metaclass=abc.ABCMeta):   # 抽象类是用来被子类继承的,不是用来实例化的
    tag=&#39;123123123123123&#39;
    @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__ = &#39;Linhaifeng&#39;
#一切皆文件
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
    all_type=&#39;file&#39;
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def read(self):
        &#39;子类必须定义读功能&#39;
        pass
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        &#39;子类必须定义写功能&#39;
        pass
# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print(&#39;文本数据的读取方法&#39;)
    def write(self):
        print(&#39;文本数据的读取方法&#39;)
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print(&#39;硬盘数据的读取方法&#39;)
    def write(self):
        print(&#39;硬盘数据的读取方法&#39;)
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print(&#39;进程数据的读取方法&#39;)
    def write(self):
        print(&#39;进程数据的读取方法&#39;)
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中文網其他相關文章!

陳述:
本文轉載於:jianshu.com。如有侵權,請聯絡admin@php.cn刪除