基础:单继承

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print(f"{self.name} 发出声音")


class Dog(Animal):                # 继承 Animal
    def speak(self):              # 覆盖父类方法
        print(f"{self.name} 汪汪")


class Cat(Animal):
    def speak(self):
        print(f"{self.name} 喵喵")


for animal in [Dog("Rex"), Cat("Mimi"), Animal("XX")]:
    animal.speak()
# Rex 汪汪
# Mimi 喵喵
# XX 发出声音

多态:同一段代码(animal.speak())对不同类型有不同行为。

super():调用父类方法

子类想"在父类基础上加点料":

class Animal:
    def __init__(self, name):
        self.name = name


class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)         # 先让父类初始化
        self.breed = breed


d = Dog("Rex", "柴犬")
print(d.name, d.breed)

isinstance / issubclass

isinstance(Dog("Rex"), Dog)        # True
isinstance(Dog("Rex"), Animal)     # True   Dog 是 Animal 的子类
issubclass(Dog, Animal)            # True

写函数时优先 isinstance 而不是 type(x) == X——前者支持子类。

多继承(慎用)

class Swimmer:
    def swim(self):
        print(f"{self.name} 在游")

class Flyer:
    def fly(self):
        print(f"{self.name} 在飞")

class Duck(Animal, Swimmer, Flyer):
    pass

d = Duck("Donald")
d.speak()    # Donald 发出声音
d.swim()     # Donald 在游
d.fly()      # Donald 在飞

MRO:方法解析顺序

多继承时方法找谁?看 MRO:

class A:
    def hello(self): print("A")

class B(A):
    def hello(self): print("B")

class C(A):
    def hello(self): print("C")

class D(B, C):
    pass

D().hello()           # B
print(D.__mro__)
# (D, B, C, A, object)

Python 用 C3 线性化算法——简单理解:左边的父类优先,但跳过共同祖先重复。

super() 的真相

super() 不一定调"直接父类"——它按 MRO 走下一个:

class B(A):
    def hello(self):
        super().hello()    # 在 D 的 MRO 里,super() 是 C 不是 A
        print("B")

理解这点对设计 mixin 很重要。

继承的"陷阱":何时不该继承

# 反例:用继承复用代码
class List(list):           # 想给 list 加点功能
    def first(self):
        return self[0]

子类化内置类型很容易踩坑。优先组合(持有对象) over 继承(继承对象)

class MyList:
    def __init__(self):
        self._data = []         # 内部持有 list

    def first(self):
        return self._data[0]

"继承表达类型关系,不是为了省代码"

经验法则:

  • "Dog Animal" → 继承
  • "Engine 属于 Car" → 组合(持有对象)

下一篇讲抽象基类 ABC 与 Protocol——把"鸭子类型"形式化。