继承
大家好,接下来我们来讲解面向对象中的继承。
简介
继承是面向对象编程中的三大概念之一,指的是一个类基于另一个类来创建。
创建出来的新类称为子类或派生类。被继承的类称为父类或基类。
通过继承,子类可以继承父类的属性和方法,并且可以在此基础上添加新的属性和方法,或者对继承的属性和方法进行修改。
继承是面向对象编程中的一个非常重要的概念,指的是一个类基于另一个类来创建。它的作用就像是子女继承父母的基因,子类可以继承父类的属性和方法。创建出来的新类称为子类或派生类。被继承的类称为父类或基类。这意味着子类可以直接使用父类已有的功能,而不需要重新写一次,简化了代码量。举个例子,想象你有一个动物类,这个类有吃和睡这些方法。然后,你想创造一个狗类,这个类当然也会吃和睡,但它还需要有叫这个额外功能。通过继承,狗类就能自动获得吃和睡这两个功能,然后你只需要在狗类里加上叫的功能即可。
继承的主要特点包括:
-
继承关系:继承创建了一个父类和子类之间的关系。子类继承了父类的特性,包括属性和方法。子类可以重用父类的代码,减少了代码的冗余。
-
子类的扩展:子类可以在继承父类的基础上,添加新的属性和方法。这样可以对父类进行扩展,使得子类具有更多的功能。
-
代码共享和重用:通过继承,子类可以共享父类的代码。父类中通用的属性和方法可以被多个子类继承和使用,提高了代码的重用性,并减少了开发时间和成本。
-
继承的层次结构:继承可以形成一个层次结构,其中一个父类可以有多个子类,而子类又可以成为其他子类的父类。这种层次结构可以更好地组织和管理代码,使得代码更加结构化和模块化。
继承带来的好处有几个:首先,继承让父类和子类之间建立了联系,子类“拿到了”父类的属性和方法,避免了重复写代码。第二,子类不仅能继承父类的功能,还可以在此基础上扩展,给自己添加新的属性或方法。第三,通过继承,多个子类可以共享父类的代码,这让我们避免重复造轮子,提升了开发效率。第四,继承也能帮我们组织代码,父类可以有多个子类,子类又可以继承更多的子类,形成一个有序的结构。
继承的优势包括:
-
代码重用:继承允许子类重用父类的代码,减少了代码的冗余,提高了代码的可维护性和复用性。
-
扩展性:通过继承,子类可以在父类的基础上添加新的属性和方法,实现对父类的扩展,使得子类具有更多的功能。
-
类型的兼容性:由于子类继承了父类的特性,子类可以被当作父类的实例来使用。这样,在需要父类类型的地方,可以使用子类的实例,增加了代码的灵活性和可扩展性。
继承的优势其实很简单,就是“复用”和“扩展”。代码重用:子类可以直接复用父类的代码,减少了不必要的重复,节省了开发时间。扩展性:继承让我们能在现有的功能基础上增加更多的功能。比如继承一个通用类,然后在此基础上做一些个性化的扩展。类型兼容:因为子类继承了父类的属性和方法,我们可以把子类对象当作父类对象来用。这样就能增加代码的灵活性。
需要注意的是,虽然继承可以提供代码重用和扩展的好处,但过度使用继承可能导致代码的复杂性和耦合性增加。因此,在设计代码时,应该合理使用继承,并遵循单一责任原则和开闭原则,保持代码的简洁和灵活。
不过,尽管继承看起来很强大,但如果用得过多也会增加代码的复杂性,导致耦合过高。所以,设计时要合理使用继承,避免过度依赖它。
单继承
单继承是指一个子类只继承一个父类。
class A(object):
# A 继承自 object 根类
def show(self):
print("父类A的方法")
class B(A):
# B类 继承自 A类
def display(self):
print("子类B的方法")
b = B()
# 子类对象使用自己的方法
b.display()
# 子类对象使用父类的方法,如果父类有没有该方法则继续向上查找,直到根类
b.show()
单继承就是一个子类只继承一个父类。简单来说,你只有一个父母,孩子就继承父母的基因。举个例子,假设你有一个父类A,它有一个方法show()。然后你创建了一个子类B,它继承了A,因此B也能使用show()方法。这样,子类就可以复用父类的方法,减少了代码重复。
方法重写
在子类中,可以对父类中的方法实现进行重写,实现新的功能实现。
class A(object):
# A 继承自 object 根类
def show(self):
print("父类A的方法")
class B(A):
# 子类重写父类方法
def show(self):
print("子类B的方法")
b = B()
# 当子类方法与父类方法同名时,调用子类方法
b.show()
在子类中,你可以选择重新定义父类的方法,这叫做“方法重写”。如果父类和子类有相同名字的方法,调用时会优先执行子类的版本。比如,父类A有一个show()方法,子类B也有一个show()方法。那么当你调用show()时,子类的show()会被调用,而不是父类的。
super()
如果在子类中还要使用父类中的方法,可以使用 super() 函数来调用父类中的方法。
比如在重写父类方法时,还要保留父类方法的功能。
class A(object):
# A 继承自 object 根类
def show(self):
print("父类A的方法")
class B(A):
# 子类重写父类方法
def show(self):
# 使用 super() 调用父类方法
super().show()
print("子类B的方法")
b = B()
# 当子类方法与父类方法同名时,调用子类方法
b.show()
如果你在子类中重写了父类的方法,但又想保留父类方法的一部分功能,可以使用super()来调用父类的版本。举个例子,子类B重写了show()方法,但是它想先执行父类的show(),然后再执行自己新增的功能。那么就可以用super().show()来实现。
单继承的初始化
在子类对象初始化时,需要给出父类初始化所需的参数,然后使用 super() 调用父类初始化方法去初始化父类的属性。
class A(object):
# A 继承自 object 根类
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
super().__init__(a)
self.b = b
b = B("A","B")
print(b.a)
print(b.b)
在初始化子类对象时,子类有时需要初始化父类的属性。你可以通过 super 来调用父类的初始化方法,确保父类的属性也能正确初始化。
继承的访问控制
无论在方法的重写,还是初始化时,父类的工作就让父类自己去完成,子类只负责自己部分的实现。
比如:如果在初始化时,想在子类中初始化父类的一个私有属性,这是不能实现的,但是可以调用父类的初始化方法对私有属性进行初始化。
class A(object):
# A 继承自 object 根类
def __init__(self, a, b, c):
self.a = a
self._b = b
self.__c = c
def show(self):
print(f"A: {self.a}")
print(f"B: {self._b}")
print(f"C: {self.__c}")
class B(A):
def __init__(self,a,b,c,d):
super().__init__(a,b,c)
self.d = d
def show(self):
super().show()
print(f"D: {self.d}")
b = B(1,2,3,4)
b.show()
在继承时,如果父类有私有属性(以双下划线__开头),子类不能直接访问这些私有属性。但你可以通过调用父类的初始化方法来间接访问它们。举个例子,父类A有私有属性__c,虽然子类B不能直接访问它,但可以通过super()调用父类的show()方法来显示它。
多继承
多继承是指一个子类可以同时继承多个父类,此时子类同时拥有多个父类中的属性和方法
class FA(object):
def fa_show(self):
print("FA Show Run...")
class FB(object):
def fb_show(self):
print("FB Show Run...")
class S(FA, FB):
def s_show(self):
print("S Show Run...")
s = S()
s.s_show()
s.fa_show()
s.fb_show()
多继承是指一个子类可以继承多个父类。想象一下,如果你有两个父母,子类就可以继承两者的基因,拥有两个父类的属性和方法。比如,父类FA有一个 fa_show 方法,父类FB有一个 fb_show 方法。然后你创建了一个子类S,它继承了这两个父类的所有功能。那么使用子类S的实例,就可以调用到这两个父类中定义的方法了。
多继承同名方法查找顺序
如果在一个子类所继承的多个父类中,具有同名方法,那么在调用该方法名的方法时,Python 会使用 C3 算法实现的 MRO(方法解析顺序)顺序来确定查找的先后顺序,一般情况可以理解成是按继承类的书写顺序。
class FA(object):
def show(self):
print("FA Show Run...")
class FB(object):
def show(self):
print("FB Show Run...")
class S(FB, FA):
def s_show(self):
print("S Show Run...")
s = S()
s.s_show()
s.show()
如果多个父类有同名方法,Python会按照继承的顺序来查找方法。我们可以通过C3算法理解这个查找顺序。一般来说,Python会从左到右查找父类,找到方法就停止。所以如果我们使用S的实例调用父类中的 show 方法的话,实际上调用到的是 FB 中的 show 方法。
多继承初始化
在多继承中,由于有多个父类,每个父类的属性都需要单独初始化,这时 super() 函数只能引用继承书写顺序上的第一个父类,其它的父类是无法通过 super() 引用的,所以也就无法利用 super 函数进行初始化。
此时,可以使用直接指定父类名的方式调用该父类中的方法。
此方法也适用于多继承中的方法重写。
class FA(object):
def __init__(self, a):
self.a = a
class FB(object):
def __init__(self, b):
self.b = b
class S(FB, FA):
def __init__(self, a, b, c):
FA.__init__(self, a)
FB.__init__(self, b)
self.c = c
c = S(1,2,3)
print(c.a)
print(c.b)
print(c.c)
在多继承中,子类继承了多个父类,所以初始化时需要分别初始化每个父类的属性。super 只能调用继承顺序中的第一个父类,因此其他父类的初始化方法需要手动调用。
总结
- 单继承
- 多继承
最后我们来总结一下。这个章节介绍的是继承。其中,单继承是指一个子类只继承一个父类,子类可以重用父类的代码,进行扩展。多继承是指一个子类可以继承多个父类,继承多个父类的功能,但需要注意继承顺序和初始化问题。