一、概述

  面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
  通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”,继承的过程,就是从一般到特殊的过程。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

继承概念的实现方式主要有2类:实现继承、接口继承

  1. 实现继承是指使用基类的属性和方法而无需额外编码的能力。
  2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构父类方法)。

  OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

二、代码实例

  • 子类:Son类
  • 父类:Father类

以下案例均表示Son类继承父亲的一些属性和初始化参数构造等。

五个模块:

  1. 直接调用父类属性方法
  2. 重写父类属性方法
  3. 强制调用父类私有属性方法
  4. 调用父类init方法
  5. 继承父类初始化过程中的参数


1).调用父类属性方法

  1. class Father():
  2. def __init__(self):
  3. self.a='aaa'
  4. def action(self):
  5. print('调用父类的方法')
  6. class Son(Father):
  7. pass
  8. son=Son() # 子类Son 继承父类Father的所有属性和方法
  9. son.action() # 调用父类方法   输出结果:调用父类的方法
  10. son.a # 调用父类属性   输出结果: aaa

2).重写父类属性方法

注意:在上面的例子中,子类Son没有属性和action的方法,所以会从父类调用,那我们再来看看,子类Son有自身的属性和方法的结果是怎样的?

  1. class Father():
  2. def __init__(self):
  3. self.a='aaa'
  4. def action(self):
  5. print('调用父类的方法')
  6. class Son(Father):
  7. def __init__(self):
  8. self.a='bbb'
  9. def action(self):
  10. print('子类重写父类的方法')
  11. son=Son() # 子类Son继承父类Father的所有属性和方法
  12. son.action() # 子类Son调用自身的action方法而不是父类的action方法
  13. son.a
  14. 输出结果:
  15. 子类重写父类的方法
  16. bbb

这里,子类Son已经重写了父类Father的action的方法,并且子类Son也有初始化,因此,子类会调用自身的action方法和属性。

总结:如果子类没有重写父类的方法,当调用该方法的时候,会调用父类的方法,当子类重写了父类的方法,默认是调用自身的方法。

另外,如果子类Son重写了父类Father的方法,如果想调用父类的action方法,可以利用super()

  1. #如果在重新父类方法后,调用父类的方法
  2. class Father():
  3. def action(self):
  4. print('调用父类的方法')
  5. class Son(Father):
  6. def action(self):
  7. super().action()
  8. son=Son()
  9. son.action()
  10. 输出结果:
  11. 调用父类的方法

3).强制调用父类私有属性方法

如果父类的方法是私有方法,如 def action(self) 这样的话再去调用就提示没有这个方法,其实编译器是把这个方法的名字改成了 _Fatheraction(),如果强制调用,可以这样:

  1. class Father():
  2. def __action(self): # 父类的私有方法
  3. print('调用父类的方法')
  4. class Son(Father):
  5. def action(self):
  6. super()._Father__action()
  7. son=Son()
  8. son.action()
  9. 输出结果:
  10. 调用父类的方法

4).调用父类的init方法

如果自己也定义了 init 方法,那么父类的属性是不能直接调用的,比如下面的代码就会报错:

class Father():
    def __init__(self):
        self.a=a

class Son(Father):
    def __init__(self):
        pass

son=Son()
print(son.a)

image.png
修改方法:可以在 子类的 init中调用一下父类的 init 方法,这样就可以调用了

class Father():
    def __init__(self):
        self.a='aaa'

class Son(Father):
    def __init__(self):
        super().__init__()
        #也可以用 Father.__init__(self)  这里面的self一定要加上
son=Son()
print(son.a) 

输出结果:
    aaa

5).继承父类初始化过程中的参数

代码1:

class Father():
    def __init__(self):
        self.a=1
        self.b=2

class Son(Father):
    def __init__(self):
        super().__init__()
        #也可以用 Father.__init__(self)  这里面的self一定要加上
    def add(self):
        return self.a+self.b
son=Son()
print(son.add())

上述代码中,父类在初始化过程中,直接对a,b分别赋值1,2。子类利用super().init()继承了父类的初始化参数a和b,所以子类调用自身的add函数(add函数返回a和b的和)会返回结果值。

再看一下,如果不对父类初始化直接赋值,并且子类在调用父类初始化过程中,增加额外自身需要的初始化参数值。
**

class Father():
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def dev(self):
        return self.a - self.b

 #调用父类初始化参数a,b并增加额外参数c
class Son(Father):
    def __init__(self,a,b,c=10):  # 固定值: 例如默认c=10,也可以显示地将c赋值
        Father.__init__(self,a,b)  # super(Son,self).__init__(a,b).
        self.c = c
    def add(self):
        return self.a+self.b
    def compare(self):
        if self.c > (self.a+self.b):
            return True
        else:
            return False

son=Son(1,2)         # 由于c在初始化过程中默认为10,所以c可以不用显示表达出来
print(son.dev())     # 调用父类dev函数
print(son.add())     # 子类自身add函数
print(son.compare()) # 子类自身compare函数

返回结果:
image.png

如果我们只是简单的在子类Son中定义一个构造函数,其实就是相当于重构,这样子类就不能继承父类的属性了。所以我们在定义子类的构造函数时,要先继承在构造,这样我们也能获取父类的属性了。

**子类构造函数基础父类构造函数过程如下:

  1. 实例化对象Son
  2. Son调用子类init()
  3. 子类init()继承父类init()
  4. 调用父类init()