继承
1.什么是继承
继承就是为了解决两个有大量重复性代码的类。 # 抽象出一个更抽象的类放公共代码。
# 其意义是重用代码,方便代码的管理与修改
# 类的继承包括属性和方法(私有属性及方法也可被继承)
# 所有类的父类: object ---- 超类
2.实现继承
子承父业
class Father():
def __init__(self, name):
self.name = name
def myself(self):
print(f'{self.name}在 Father类里面')
class Son(Father):
pass
s = Son('son')
print(dir(s))
# __class__:查看实例名 __mro__:查看搜索顺序
print(s.__class__.__mro__)
注意:MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
3.补充:
class A():
name = 'A'
def is_who(self):
print('这是A')
class B(A):
def __init__(self):
self.age = 8
def is_where(self):
print('这是B')
demo = B()
# 我去调用实例对象 demo 里面某个方法或者属性时,其内部寻找是先找对象本身,找不到就依据mro继承顺序逐个寻找,找到就调用,且不会继续向后寻找。
# 注意属性为了避免一些问题,都是通过初始化加给到对象
4.多继承
class Base():
name = 'A'
def play(self):
print('这是Base')
class A(Base):
age = 18
def play(self):
print('这是A')
class B(Base):
def play(self):
print('这是B')
# 注意:如果B继承A会出现问题哦,因为下面的属于多继承,不是套娃
# 同时:注意一点,继承会继承所有的 属性及方法
class C(A, B):
pass
s = C()
s.play()
print(C.__base__)
print(C.__mro__) # 查找顺序------- 核心点:继承顺序mro
# 继承优先前面,也就是先看A,然后看B
5.重构
class Base():
name = 'A'
def play(self):
print('这是Base')
class A(Base):
age = 18
def play(self):
print('这是A')
class B(Base):
def play(self):
print('这是B')
class C(A, B):
pass
# 在我们操作的时候会发现一个问题,那就是:
s = C()
s.play()
# 调用的是直系父类A的play方法,这就与我们之前讲的调用顺序一样的:对象里面找不到就去类里面找(mro顺序),找到就调用,且不会向后寻找
# 同时记住一点:我们的对象的方法都在类里面定义出来的
# 基于以上两个点我们就出现了一个操作: 重写方法(重构)
# 多继承中,父类与子类 存在 名字相同的方法,
# 当子类实例化后调用此方法, 调用的是子类的
6.定向继承
super指定继承需要有继承关联
super(): 是用于调用父类的一个方法,遵循就近原则
super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
class Base():
def play(self):
print('这是Base')
class Base2():
def play(self):
print('这是Base2')
class A(Base2):
def play(self):
print('这是A')
class B(Base):
def play(self):
print('这是B')
class C(A, B):
def play(self):
# super
super().play() # super()默认找当前类的父类
# super(A, self).play() # 指定继承(需要在mro继承表里面)
# 根据继承搜索顺序
print('这是C')
C().play()
7.指定性继承
这种方式看似可以逾越继承以及关系,但是缺点极大
class Base():
def __init__(self, name):
self.name = name
def demo(self):
print(1)
class SonS(Base):
def sd(self):
# 指定性继承 方式一 --- 注意方法中不能存在调用对象属性或方法,
# 同时注意传参,除了对象传入,还有定义的参数(没有就不管)
Base.demo(self)
# 指定性继承 方式二 --- 临时实例化对象,通过这个对象调用里面方法或属性(注意初始化,及传参)
# Base(name=1).demo()
a = SonS(2)
a.sd()