Python中的super()面向对象编程
目录
- 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)
执行顺序图
到此这篇关于Python super()面向对象编程的文章就介绍到这了,更多相关Python super()内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
赞 (0)