Python教程 - 继承

529 阅读4分钟

当开始使用 Python 的类(class)解决问题时,通常会遇到需要修改类的情况,这往往会导致原始类变得复杂或破坏原有功能。这时就需要使用类中的“继承”方式来处理。这篇教程将介绍 Python 中的“继承”。

什么是继承(inheritance)?

继承,就像字面上的意思:父亲继承了爷爷的东西,儿子继承父亲的东西...不断继承下去,继承表示可以用现有的类去定义一个新的类,并加入一些新的东西或修改新的类。当使用继承时,新类会自动使用旧类内所有的代码。

下面的代码,名为 son 的类使用class son(father)的语法,继承了 father 的代码。当 oxxo 为 son 时,就能调用出 father 的所有属性。

class father():         # fatehr 类
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class son(father):          # son 类继承了 fatehr 类里所有的方法
    def language(self):     # son 类具有 language 的方法
        print('chinese')    # 从 father 继承了五官,然后自己学会讲中文

oxxo = son()                # 设定 oxxo 为 son()
print(oxxo.eye)             # 打印出 2
oxxo.language()             # 打印出 chinese

继承时会覆盖方法

在继承时,如果子类中的某个方法的名称和父类相同,就会完全复写父类的方法。下面的代码,son 类使用了 init 的方法,就覆盖了原本 father 的 init 方法,导致读取 oxxo.ear 时发生错误(因为 son 的方法里不存在 ear 的属性)。

class father():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class son(father):
    def __init__(self):   # 使用了 __init 的方法
        self.eye = 100

oxxo = son()
print(oxxo.eye)    # 100
print(oxxo.ear)    # 发生错误  'son' object has no attribute 'ear'

使用 super()

如果不想要覆盖父类的方法,又想要使用父类的方法,就可以使用super()来实现。下面的代码,使用 super()继承了 father init 里所有的属性,然后再将 eye 的属性覆盖为 100。

class father():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class son(father):
    def __init__(self):
        super().__init__()   # 使用 super() 继承 father __init__ 里所有属性
        self.eye = 100       # 如果属性相同,则覆写属性

oxxo = son()
print(oxxo.eye)              # 100
print(oxxo.ear)              # 2

多重继承

继承不仅可以进行单一继承,也可以进行多重继承,例如可以从爸爸身上继承基因,同时也可以妈妈身上继承基因。一般情况下,下面的例子,son 从 father 继承了五官,从 mother 继承了 language 和 skill。

class father():          # father 类
    def __init__(self):  # father 的方法
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class mother():          # mother 类
    def language(self):  # mother 的方法
        print('english')
    def skill(self):
        print('painting')

class son(father, mother):    # 继承 father 和 mother
    def play(self):           # son 自己的方法
        print('ball')

oxxo = son()
print(oxxo.eye)        # 2
oxxo.skill()           # painting
oxxo.play()            # ball

进行多重继承时,同样会有“覆盖方法”的情况出现,而覆盖方法的顺序是由“读取类的顺序”决定的,举个例子来说,下面的 c 和 d 两个类,虽然都多重继承了 a 和 b,但是因为读取的顺序不同,所以呈现的结果也会不同。

class a():
    def says(self):
        print('a')

class b():
    def says(self):
        print('b')

class c(a, b):    # 先读取 a 再 b,就会将 a 里的方法,覆写 b 里同名的方法
    pass

class d(b, a):    # 先读取 b 再 a,就会将 b 里的方法,覆写 a 里同名的方法
    pass

ccc = c()
ddd = d()
ccc.says()    # a
ddd.says()    # b

多层继承

继承中除了多重继承,也有“多层继承”的概念,就如同父亲继承了爷爷的东西,儿子继承父亲的东西,多层继承同样存在覆盖方法的原则,如果遇到同名的方法就会覆盖,除非使用 super()的方法处理,下面的例子里,father 继承了 grandpa 的五官,son 又继承了 father 的方法,最后 son 就拥有 father 和 grandpa 所有的方法。

class grandpa():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class father(grandpa):
    def language(self):
        print('english')
    def skill(self):
        print('painting')

class son(father):
    def play(self):
        print('ball')

oxxo = son()
print(oxxo.eye)    # 2
oxxo.skill()       # painting
oxxo.play()        # ball

私有方法(双下划线)

在实现一个类的过程中,可能会遇到有些方法是该类内部使用,不想让继承该类的子类可以使用的,这时就需要定义“私有方法”,私有方法可以使用“双下划线+名称”来定义,私有方法定义后,无论是从外部读取或是子类的继承,都无法使用该方法,只有在该类里的其他方法才能调用。

下面的代码 grandpa 有一个__money 的方法,但除非知道 getMoney 的方法,不然都无法直接读取(爷爷有一笔钱,除非你知道方法,否则无法继承成功)。

class grandpa():
    def __init__(self):
        self.mouth = 1
    def __money(self):     # 定义一个私有方法 __money
        print('$1000')
    def getMoney(self):    # 定义一个 getMoney 的方法,执行私有方法 __money
        self.__money()

class father(grandpa):
    def skill(self):
        print('painting')

class son(father):
    def play(self):
        print('ball')

oxxo = son()
oxxo.getMoney()         # $1000
oxxo.__money()          # 发生错误  'son' object has no attribute '_money'