信息发布→ 登录 注册 退出

详析Python面向对象中的继承

发布时间:2026-01-11

点击量:
目录
  • 一 单继承
    • 1. 继承的基本语法格式如下
    • 2. 查看类继承情况
    • 3. 继承中的属性和方法
    • 4. 初始化函数__init__()和 super
  • 二 多层继承
    • 三 多重继承

      一 单继承

      类继承作为python的三大特性之一,在我们学习python的时候是必不可少的。使用类继承,能够大大减少重复代码的编写。现来记录下,python中关于类继承的一些知识点。
      类的继承有单继承,多层继承以及多重继承,先来看看单继承。

      1. 继承的基本语法格式如下

      #类继承语法格式,B类继承A类
      class A():
          类属性
          类方法
          ...
      class B(A):
          类属性
          类方法
          ...

      单继承的话一般类A是没有继承其他派生类的,只继承了基类。因为在python新式类中,一个类会默认去继承基类object的,基类object是顶级类。

      2. 查看类继承情况

      class Father():
          #这是父类
          name1 = 'father_name'
          age1 = 'father_age'
          def father_method(self):
              print('我是父亲')
      
      class Son(Father):
          #这是子类
          name2 = 'son_name'
          age2 = 'son_age'
          def son_method(self):
              print('我是孩子')
      
      if __name__ == '__main__':
          A = Father()
          B = Son()
          #单继承
          print(B.__class__.__mro__)
          #或者Son.mro()
          print(Son.mro())

      如上:我们定义了一个父类Father,一个子类Son,并且子类Son继承父类Father,它们都有自己的属性和方法。我们可以通过打印B.__ class__.__mro __ 或者Son.mro()来查看Son类的继承情况,如下:

      >>>
      (<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>)
      [<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>]

      可以看到,Son类确实继承了Father类,并且继承基类object。

      3. 继承中的属性和方法

      如果一个类继承了另外一个类,那么这个类是可以调用其继承类的属性和方法的(子类可以调用父类的属性和方法),如下

      class Father():
          #这是父类
          name1 = 'father_name'
          age1 = 'father_age'
          def father_method(self):
              print('我是父亲')
      
      class Son(Father):
          #这是子类
          name2 = 'son_name'
          age2 = 'son_age'
          def son_method(self):
              print('我是孩子')
      
          def fun1(self):
              #调用父类属性和方法
              print(self.age1, self.name1)
              self.father_method()
      
      if __name__ == '__main__':
          A = Father()
          B = Son()
          #单继承
          # print(B.__class__.__mro__)
          B.fun1()

      结果如下:

      >>>
      father_age father_name
      我是父亲

      当子类中的属性名方法名和父类中的属性名方法名同名时,在该子类中会覆盖父类的属性名和方法名(重写)。

      class Father():
          #这是父类
          name1 = 'father_name'
          age1 = 'father_age'
          def father_method(self):
              print('我是父亲')
      
      class Son(Father):
          #这是子类
          name1 = 'son_name'
          age1 = 'son_age'
          def son_method(self):
              print('我是孩子')
      
          def father_method(self):
              #和父类方法同名,将以子类方法为准
              print("与父类方法同名,但是我是子类")
      
          def son_fun1(self):
              #调用父类属性
              print("子类属性和父类属性同名,以子类为准:", self.name1, self.age1)
      
      
      if __name__ == '__main__':
          A = Father()
          B = Son()
          #单继承
          # print(B.__class__.__mro__)
          B.father_method()
          B.son_fun1()

      输出如下:

      >>>
      与父类方法同名,但是我是子类
      子类属性和父类属性同名,以子类为准: son_name son_age

      4. 初始化函数__init__()和 super

      上面写的子类和父类都是不需要传参数的,而当我们需要给类传参数时,往往都是要初始化的,下面来看看子类继承父类时,参数初始化的几种情况。

      子类无新增参数:

      class Father():
          #父类
          def __init__(self, name='张三', age=23):
              self.name = name
              self.age = age
      
      class Son(Father):
          #子类
          def son_fun1(self):
              print(self.name, self.age)
      
      if __name__ == '__main__':
          B = Son()
          B.son_fun1()

      输出:

      >>>
      张三 23

      如上,在子类无新增参数时,无需进行__init__ 初始化,直接调用父类的对象属性即可。因为子类Son是继承自父类Father的,所以在调用时会首先去调父类的__init__ 进行初始化

      子类有新增参数:

      当子类有新增参数时,该怎么初始化呢?先来看看这个对不对

      class Father():
          #父类
          def __init__(self, name='张三', age=23):
              self.name = name
              self.age = age
      
      class Son(Father):
          #子类
          def __init__(self, height):
              self.height = height
      
          def son_fun1(self):
              print(self.height)
              print(self.name, self.age)
      
      if __name__ == '__main__':
          B = Son(170)
          B.son_fun1()

      输出:

      >>>
      AttributeError: 'Son' object has no attribute 'name'
      170

      上面子类Son新增了一个height参数,然后用__init__ 进行初始化。但是从输出结果可以看出,height参数是正常打印的,打印name和age参数时就报错:子类Son没有属性’name’,因为这个时候就不会去调用父类的__init__ 进行初始化,而是直接调用子类中的__init__ 进行初始化,这时,子类初始化就会覆盖掉父类的__init__ 初始化,从而报错。

      正确的初始化有两种方法,如下:

      #方法1
      def __init__(self, 父类参数1, 父类参数2, ..., 子类参数1, 子类参数2, ...)
          父类名.__init__(self, 父类参数1, 父类参数2, ...)
          self.子类属性 = 子类属性
      
      class Father():
          #父类
          def __init__(self, name='张三', age=23):
              self.name = name
              self.age = age
      
      class Son(Father):
          #子类
          def __init__(self, name, age, height):
              #方法1
              Father.__init__(self, name, age)
              self.height = height
      
          def son_fun1(self):
              print(self.height)
              print(self.name, self.age)
      
      if __name__ == '__main__':
          B = Son('李四', 24, 170)
          B.son_fun1()

      >>>
      175
      李四 24

      从结果可以看出,调用父类初始化后,结果就正常输出。这是在子类__init__初始化的时候,调用了Father.__ init __(self, name, age)对父类对象属性进行了初始化。

      现在来看看另外一个初始化方法super()初始化,不过使用super()的时候要注意python的版本,因为python2和python3的使用是不同的,如下

      #方法2
      def __init__(self, 父类参数1, 父类参数2, ..., 子类参数1, 子类参数2, ...): 
          #python2的super初始化
          super(子类名, self).__init__(父类类参数1, 父类参数2, ...)
          self.子类属性 = 子类属性
          #python3的super初始化
          super().__init__(父类类参数1, 父类参数2, ...)
          self.子类属性 = 子类属性
      
      
      class Father():
          #父类
          def __init__(self, name='张三', age=23):
              self.name = name
              self.age = age
      
      class Son(Father):
          #子类
          def __init__(self, name, age, height):
              #方法2
              #python2的super初始化
              super(Son, self).__init__(name, age)
              self.height = height
              #python3的super初始化
              # super().__init__(name, age)
              #或者 super(Son, self).__init__(name, age)
              
          def son_fun1(self):
              print(self.height)
              print(self.name, self.age)
      
      if __name__ == '__main__':
          B = Son('李四', 24, 175)
          B.son_fun1()

      结果:

      >>>
      175
      李四 24

      上面使用的是super(Son, self).__ init __ (name, age) 来对父类对象属性进行初始化。不过这是要区分python版本的,在python3中使用super(Son, self).__ init__(name, age)或者super().__ init__(name, age)都是可以的,但是在python2的版本中,要使用super(Son, self).__ init__(name, age)来进行初始化,而且父类必须继承object,否则就会报错。

      二 多层继承

      上面的记录的是单继承,现在来看看多层继承。多层继承:子类继承自多个父类,父类只继承自object顶级类。

      class Father():
          def __init__(self):
              print("enter father")
              print("leave father")
      
          def fun(self):
              print("这是father")
      
      class Mother():
          def __init__(self):
              print("enter mother")
              print("leave mother")
      
          def fun(self):
              print("这是mather")
      
      class Son(Father, Mother):
          def __init__(self):
              print("enter son")
              super().__init__()
              print("leave son")
      
      if __name__ == '__main__':
          B = Son()
          B.fun()
          print(Son.mro())

      输出:

      >>>
      enter son
      enter father
      leave father
      leave son
      这是father

      继承关系:

      [<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>]

      这里有两个父类Father,Mother,一个子类Son,子类Son继承了类Father和Mother,继承顺序是Father在前,Mother在后。从上面输出结果来看,子类初始化过程是先进入子类Son的 __ init __方法,其次调用super(). __init __()进行父类对象属性初始化,最后初始化完成。
      从结果可以知道上面super初始化调用的是父类Father的 __ init __方法。
      。也可以看出,类Father和类Mother都有一个fun方法(同名),但在子类调用时调的是父类father的fun方法。这是为什么呢?

      这里就涉及到super的继承机制,即super会根据MRO机制,从左到右依次调用父类的属性和方法, 当父类中有同属性名,同方法名时,以靠左的那个父类为准。

      下面我们把Father和Mother位置换一下,如下:

      class Father():
          def __init__(self):
              print("enter father")
              print("leave father")
      
          def fun(self):
              print("这是father")
      
      class Mother():
          def __init__(self):
              print("enter mother")
              print("leave mother")
      
          def fun(self):
              print("这是mather")
      
      class Son(Mother, Father):#这里变动,变换Father和Mother的位置
          def __init__(self):
              print("enter son")
              super().__init__()
              print("leave son")
      
      if __name__ == '__main__':
          B = Son()
          B.fun()
          print(Son.mro())

      结果:

      >>>
      enter son
      enter mother
      leave mother
      leave son
      这是mather
      [<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]

      继承关系:

      >>>
      [<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]

      可以看出,当Mother在前时,调用的就是类Mather的初始化方法和fun方法。所以在多层继承时,一定要注意父类的位置顺序。

      三 多重继承

      其实super的产生就是用来解决多重继承问题的,什么是多重继承呢?即,子类继承多个父类,而父类又继承自其它相同的类,这种又被称为菱形继承或者砖石继承,

      如下:

           A
         /   \
        /     \
       B       C
        \     /
         \   /
           D

      先来看看如下的一个菱形继承:

      class A():
          def __init__(self):
              print("enter A")
              print("leave A")
      
      class B(A):
          def __init__(self):
              print("enter B")
              # super().__init__()
              A.__init__(self)
              print("leave B")
      
      class C(A):
          def __init__(self):
              print("enter C")
              # super().__init__()
              A.__init__(self)
              print("leave C")
      
      class D(B, C):
          def __init__(self):
              print("enter D")
              B.__init__(self)
              C.__init__(self)
              # super().__init__()
              print("leave D")
      
      if __name__ == '__main__':
          d = D()

      输出结果:

      >>>
      enter D
      enter B
      enter A
      leave A
      leave B
      enter C
      enter A
      leave A
      leave C
      leave D
      [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

      上面用的是父类名. __ init__ () 来进行子类初始化的,但是从结果来看,类A的初始化方法是被执行了两次的,一次是类B的调用,一次是类C的调用。也可以看出子类D的初始化 __ init __ 调用了B.__ init __() 和C. __init __() 。现在D类继承的父类只有B和C,但是当代码比较复杂,继承的类比较多时,就得的一个一个写,如果类B和类C也是继承自多个类,那它们的初始化方法也得重新写,这样就比较繁琐,也容易出错。

      下面来使用super初始化父类看看:

      class A():
          def __init__(self):
              print("enter A")
              print("leave A")
      
      class B(A):
          def __init__(self):
              print("enter B")
              super().__init__()
              print("leave B")
      
      class C(A):
          def __init__(self):
              print("enter C")
              super().__init__()
              print("leave C")
      
      class D(B, C):
          def __init__(self):
              print("enter D")
              super().__init__()
              print("leave D")
      
      if __name__ == '__main__':
          d = D()
          print(D.mro())

      输出结果:

      enter D
      enter B
      enter C
      enter A
      leave A
      leave C
      leave B
      leave D
      [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

      可以看到输出结果是不一样的,类A的初始化只执行了一次,而且当D类有新增父类时,初始化方法也不用动,从而避免重写初始化方法出错,代码也变得整洁。
      这里还是和super的继承机制有关,上面说过当子类继承自多个父类时,super会根据MRO机制,从左到右依次调用父类的属性和方法,而且使用super初始化父类时,会一次性初始化所有的父类,所以上面的类A初始化方法不会被调用两次。

      所以在类的多重继承中,一般建议使用super来初始化父类对象属性。

      在线客服
      服务热线

      服务热线

      4008888355

      微信咨询
      二维码
      返回顶部
      ×二维码

      截屏,微信识别二维码

      打开微信

      微信号已复制,请打开微信添加咨询详情!