新闻动态

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

发布日期:2022-01-25 18:49 | 文章来源:脚本之家

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)
 

执行顺序图


到此这篇关于Python super()面向对象编程的文章就介绍到这了,更多相关Python super()内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

版权声明:本站文章来源标注为YINGSOO的内容版权均为本站所有,欢迎引用、转载,请保持原文完整并注明来源及原文链接。禁止复制或仿造本网站,禁止在非www.yingsoo.com所属的服务器上建立镜像,否则将依法追究法律责任。本站部分内容来源于网友推荐、互联网收集整理而来,仅供学习参考,不代表本站立场,如有内容涉嫌侵权,请联系alex-e#qq.com处理。

相关文章

实时开通

自选配置、实时开通

免备案

全球线路精选!

全天候客户服务

7x24全年不间断在线

专属顾问服务

1对1客户咨询顾问

在线
客服

在线客服:7*24小时在线

客服
热线

400-630-3752
7*24小时客服服务热线

关注
微信

关注官方微信
顶部