当前位置 博文首页 > Python中的super()面向对象编程

    Python中的super()面向对象编程

    作者:小菠萝测试笔记 时间:2021-09-15 18:04

    目录
    • Python super()面向对象编程
      • 一、为什么要用 super()
      • 二、什么是 super
      • 三、继承中使用 super
        • 1、实例方法使用 super
        • 2、构造方法使用 super
      • 四、多继承中使用 super

      Python super()面向对象编程

      一、为什么要用 super()

      当子类重写了父类方法时,又想调用父类的同名方法时,就需要用到 super()

      二、什么是 super

      • 在 Python 中,super 是一个特殊的类
      • super() 就是使用 super 类创建出来的对象
      • 实际应用的场景:子类在重写父类方法时,调用父类方法

      三、继承中使用 super

      1、实例方法使用 super

      类图

      实际代码

      class A:
          def __init__(self):
              self.n = 1
      
          def add(self, m):
              print(f'AAA [self] is {id(self)}')
              print(f'AAA [self.n] is {self.n}')
              self.n += m
      
      
      class B(A):
          def __init__(self):
              self.n = 100
      
          # 重写父类方法
          def add(self, m):
              # 子类特有代码
              print(f'BBB [self] is {id(self)}')
              print(f'BBB [self.n] is {self.n}')
      
              # 调用父类方法
              super().add(m)
      
              self.n += m
      
      
      b = B()
      b.add(2)
      print(b.n)
      
       
      
      # 输出结果
      BBB [self] is 4489158560
      BBB [self.n] is 100
      
      AAA [self] is 4489158560
      AAA [self.n] is 100
      
      104
      
      

      super().add()  的确调用了父类方法
      重点:此时父类方法的 self 并不是父类实例对象,而是子类实例对象

      2、构造方法使用 super

      class Animal:
          def __init__(self, name):
              self.name = name
      
          def prints(self):
              print("Animale name is ", self.name)
      
      
      class Dog(Animal):
          def __init__(self, name, age):
              # 调用父类的 init 构造方法
              super(Dog, self).__init__(name)
              self.age = age
      
          def prints(self):
              # 调用父类的方法
              super(Dog, self).prints()
              print("Dog age is ", self.age)
      
      
      dog = Dog("小汪", 10)
      dog.prints()
      
       
      
      # 输出结果
      Animale name is  小汪
      Dog age is  10
      
      

      这里用了 super(子类名, self) ,和上面的 super() 是一样效果

      调用父类方法有两种方式

      • super().父类方法() 
      • super(子类名, self).父类方法() 

      其实还有第三种

      在 Python  2.x 的时候,如果需要调用父类的方法,还可以用

      父类名.方法(self)

      • 这种方式,Python 3.x 还是支持的
      • 过不不推荐,因为父类名发生变化的话,方法调用位置的类名也要同步修改

      通过父类名调用父类方法(不推荐)

      class Animal:
          def __init__(self, name):
              self.name = name
      
          def prints(self):
              print("Animale name is ", self.name)
      
      
      class Dog(Animal):
          def __init__(self, name, age):
              # 调用父类的 init 构造方法
              Animal.__init__(self, name)
              self.age = age
      
          def prints(self):
              # 调用父类的方法
              Animal.prints(self)
              print("Dog age is ", self.age)
      
      
      dog = Dog("小汪", 10)
      dog.prints()
      
      
      # 输出结果
      Animale name is  小汪
      Dog age is  10
      
      

      通过父类名调用的这种方式,是需要传 self 参数的哦

      温馨提示:
      在开发时, 父类名.方法() super().方法() 两种方式不要混用哈

      灵魂拷问一:既然已经重写了子类的构造方法,为什么还要去调用 super?
      子类需要重写父类方法来实现子类独有的功能,但同时又需要依赖父类方法来完成某些逻辑

      实际栗子

      • 在实现多线程的时候(后面会详细展开说多线程)
      • 父类 Thread 的构造方法包含了很多逻辑代码
      • 子线程虽然需要实现子类独有功能,但仍需父类方法来处理其他逻辑

      from threading import Thread
      
      
      class MyThread(Thread):
          def __init__(self, name):
              # 1、实现子类独有功能
              print("子类线程 %s" % name)
              # 2、需要依赖父类方法完成其他功能
              super().__init__(name=name)
      

      四、多继承中使用 super

      类图

      实际代码

      # 多继承
      class Animal:
          def __init__(self, animalName):
              print(animalName, 'is an animal.')
      
      
      # Mammal 继承 Animal
      class Mammal(Animal):
          def __init__(self, mammalName):
              print(mammalName, 'is a mammal.')
              super().__init__(mammalName)
      
      
      # CannotFly 继承 Mammal
      class CannotFly(Mammal):
          def __init__(self, mammalThatCantFly):
              print(mammalThatCantFly, "cannot fly.")
              super().__init__(mammalThatCantFly)
      
      
      # CannotSwim 继承 Mammal
      class CannotSwim(Mammal):
          def __init__(self, mammalThatCantSwim):
              print(mammalThatCantSwim, "cannot swim.")
              super().__init__(mammalThatCantSwim)
      
      
      # Cat 继承 CannotSwim 和 CannotFly
      class Cat(CannotSwim, CannotFly):
          def __init__(self):
              print('I am a cat.');
              super().__init__('Cat')
      
      
      # Driver code
      cat = Cat()
      print('')
      bat = CannotSwim('Bat')
      
       
      
      # 输出结果
      I am a cat.
      Cat cannot swim.
      Cat cannot fly.
      Cat is a mammal.
      Cat is an animal.
      
      Bat cannot swim.
      Bat is a mammal.
      Bat is an animal.
      
      

      好像挺奇怪的,从输出结果看,为什么 CannotSwim 类里面的 super().__init__() 调用的是 CannotFly 类里面的方法呢?不是应该调用 CannotSwim 的父类 Mamal 的方法吗?

      灵魂拷问二:super 的执行顺序到底是什么?

      • 其实 super() 并不一定调用父类的方法
      • super() 是根据类的 MRO 方法搜索顺序来决定调用谁的
      • super() 真正调用的是 MRO 中的下一个类,而不一定是父类
      • 当然,这种情况只会出现在多继承

      先来看看 Cat 的 MRO

      print(Cat.__mro__)
      
      (<class '__main__.Cat'>, <class '__main__.CannotSwim'>, <class '__main__.CannotFly'>, <class '__main__.Mammal'>, <class '__main__.Animal'>, <class 'object'>)
      

      从 Cat 的 MRO 可以看到

      • CannotSwim 后面跟的是 CannotFly 而不是 Mamal
      • 所以 CannotSwim 类里面的 super() 会调用 CannotFly 里面的方法

      多继承的栗子二

      实际代码

      class A:
          def __init__(self):
              self.n = 2
      
          def add(self, m):
              # 第四步
              # 来自 D.add 中的 super
              # self == d, self.n == d.n == 5
              print('self is {0} @AAA.add'.format(self))
              self.n += m
              # d.n == 7
      
      
      class C(A):
          def __init__(self):
              self.n = 4
      
          def add(self, m):
              # 第三步
              # 来自 B.add 中的 super
              # self == d, self.n == d.n == 5
              print('self is {0} @CCC.add'.format(self))
              # 等价于 suepr(C, self).add(m)
              # self 的 MRO 是 [D, B, C, A, object]
              # 从 C 之后的 [A, object] 中查找 add 方法
              super().add(m)
      
              # 第五步
              # d.n = 7
              self.n += 4
              # d.n = 11
      
      
      class B(A):
          def __init__(self):
              self.n = 3
      
          def add(self, m):
              # 第二步
              # 来自 D.add 中的 super
              # self == d, self.n == d.n == 5
              print('self is {0} @BBB.add'.format(self))
              # self 的 MRO 是 [D, B, C, A, object]
              # 从 B 之后的 [C, A, object] 中查找 add 方法
              # 从 C 找 add 方法
              super().add(m)
      
              # 第六步
              # d.n = 11
              self.n += 3
              # d.n = 14
      
      
      class D(B, C):
          def __init__(self):
              self.n = 5
      
          def add(self, m):
              # 第一步
              print('self is {0} @DDD.add'.format(self))
              # self 的 MRO 是 [D, B, C, A, object]
              # 从 D 之后的 [B, C, A, object] 中查找 add 方法
              # 从 B 找 add 方法
              super().add(m)
      
              # 第七步
              # d.n = 14
              self.n += 5
              # self.n = 19
      
      
      d = D()
      d.add(2)
      print(d.n)
       
      
      

      先看看 D 类的 MRO

      print(D.__mro__)
      
      (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
      

      输出结果

      self is <__main__.D object at 0x10c14a190> @DDD.add
      self is <__main__.D object at 0x10c14a190> @BBB.add
      self is <__main__.D object at 0x10c14a190> @CCC.add
      self is <__main__.D object at 0x10c14a190> @AAA.add
      19
      

      调用顺序的确是 D、B、C、A

      执行顺序

      class D(B, C):          class B(A):            class C(A):             class A:
      def add(self, m):       def add(self, m):      def add(self, m):       def add(self, m):
      super().add(m)  1.--->  super().add(m) 2.--->  super().add(m)  3.--->  self.n += m
       self.n += 5   <------6. self.n += 3    <----5. self.n += 4     <----4. <--|
      (14+5=19)               (11+3=14)              (7+4=11)                (5+2=7)
       
      
      

      执行顺序图


      jsjbwy