1. 继承的基本语法
在 Python 中,定义一个子类时,需要在类名后面的括号中指定父类:
class 父类: # 父类的属性和方法class 子类(父类): # 子类自己的属性和方法
父类:被继承的类,也称为基类或超类。
子类:通过继承得到的新类,也称为派生类。
2. 一个简单的继承例子
从一个最基本的例子开始:定义一个 Animal 类,然后创建一个 Dog 类继承它。
# 父类class Animal: def __init__(self, name): self.name = name def speak(self): print(f"{self.name} 发出声音")# 子类继承 Animalclass Dog(Animal): def wag_tail(self): print(f"{self.name} 摇尾巴")# 使用animal = Animal("动物")animal.speak() # 输出: 动物 发出声音dog = Dog("旺财")dog.speak() # 子类继承了 speak 方法,输出: 旺财 发出声音dog.wag_tail() # 子类自己的方法,输出: 旺财 摇尾巴
说明:Dog 类没有定义 __init__ 和 speak 方法,但它从 Animal 类中继承了过来,所以可以直接使用。同时 Dog 类添加了自己的新方法 wag_tail。
3. 方法重写(Override)
子类可以对父类的方法进行重写,即在子类中定义一个与父类同名的方法,从而覆盖父类的行为。
class Cat(Animal): def speak(self): # 重写父类的 speak 方法 print(f"{self.name} 喵喵叫")cat = Cat("咪咪")cat.speak() # 输出: 咪咪 喵喵叫
这里 Cat 类重写了 speak 方法,调用时使用子类自己的实现。
4. 使用 super() 调用父类方法
有时候我们希望在子类中重写方法的同时,还能调用父类的原始方法。这可以通过 super() 函数实现。
class Bird(Animal): def __init__(self, name, can_fly=True): # 调用父类的 __init__ 来初始化 name super().__init__(name) self.can_fly = can_fly def speak(self): # 先调用父类的 speak super().speak() print("这只鸟在叽叽喳喳")bird = Bird("小麻雀")bird.speak()# 输出:# 小麻雀 发出声音# 这只鸟在叽叽喳喳
说明:
5. 多重继承
Python 支持一个子类继承多个父类,这称为多重继承。语法如下:
class 子类(父类1, 父类2, ...): # 子类内容
当多个父类中有同名方法时,Python 会按照方法解析顺序(MRO)来决定调用哪一个。
class Flyer: def fly(self): print("我能飞")class Swimmer: def swim(self): print("我能游泳")class Duck(Flyer, Swimmer): def sound(self): print("嘎嘎嘎")duck = Duck()duck.fly() # 继承自 Flyer,输出: 我能飞duck.swim() # 继承自 Swimmer,输出: 我能游泳duck.sound() # 自己的方法,输出: 嘎嘎嘎
如果多个父类中有同名方法,那么继承顺序(括号中从左到右)影响方法解析顺序。
class A: def test(self): print("A")class B: def test(self): print("B")class C(A, B): passc = C()c.test() # 输出: A (因为先继承 A)# 查看 MROprint(C.__mro__)# 输出类似: (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
注意:多重继承虽然强大,但过度使用可能导致代码复杂和难以理解,实际开发中应谨慎使用。
6. 多继承的方法解析顺序图解
为了更直观地理解多重继承中的方法查找顺序,可以画一个继承关系图,并标注出 Python 的 MRO(方法解析顺序)。Python 使用 C3 线性化算法来确定 MRO,它保证每个类在父类之前被检查,且子类优先。
下面是一个经典的“菱形继承”例子,通过图示可以看清查找顺序:
class Base: def method(self): print("Base")class Left(Base): def method(self): print("Left")class Right(Base): def method(self): print("Right")class Derived(Left, Right): pass
继承关系如如下:
当我们调用 Derived().method() 时,Python 会按照 MRO 顺序查找 method。MRO 可以通过 Derived.__mro__ 查看:
print(Derived.__mro__)# 输出: (<class '__main__.Derived'>, <class '__main__.Left'>, <class '__main__.Right'>, <class '__main__.Base'>, <class 'object'>)
对应的查找路径如图中箭头所示(从左到右):
Derived → Left → Right → Base → object
因此,Derived().method() 会首先找到 Left 中的 method 并执行,输出 "Left"。如果 Left 中没有定义,才会继续找 Right,然后是 Base。
这个顺序保证了在复杂继承层次中,方法查找不会出现歧义,也保持了单调性。
7. 继承中的几个重要函数和属性
isinstance(obj, class):判断对象是否为某个类(或其子类)的实例。
issubclass(sub, parent):判断一个类是否是另一个类的子类。
类名.__bases__:查看直接父类(以元组形式返回)。
类名.__mro__:查看方法解析顺序。
print(isinstance(dog, Animal)) # Trueprint(issubclass(Dog, Animal)) # Trueprint(Dog.__bases__) # (<class '__main__.Animal'>,)print(Dog.__mro__) # (Dog, Animal, object)
8. 总结
继承使代码复用变得简单,子类自动获得父类的非私有成员。
子类可以重写父类方法,实现多态。
super() 函数可以在子类中调用父类方法,避免硬编码父类名称。
Python 支持多重继承,但需要留意方法解析顺序(MRO)带来的影响。
合理使用继承能让程序结构清晰,易于扩展和维护。