Python 的继承就是让一个类直接拿到另一个类的属性和方法,不用重复写一遍。子类继承父类之后,父类有的东西子类全都能用,想改就重写对应的方法就行。
Python 跟 Java 不一样的地方在于它支持 多继承,一个子类可以同时继承多个父类。多继承虽然灵活,但也带来了方法冲突的问题,Python 用 MRO 来确定方法调用顺序。来看个最直观的例子:
Pythonclass Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return f"{self.name}: Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name}: Meow!"
dog = Dog("Buddy")
print(dog.speak()) # Buddy: Woof!
print(isinstance(dog, Animal)) # True
子类 Dog 和 Cat 继承了 Animal 的 init,不用重复写初始化逻辑,只需要重写 speak 方法就能实现各自的行为。isinstance 也能正确识别继承关系。
Animal 作为基类,定义了 name 属性和 speak 方法。Dog 继承 Animal,重写 speak 返回 "Woof!"。Cat 继承 Animal,重写 speak 返回 "Meow!"。
isinstance(dog, Animal) 返回 True,说明子类实例也是父类的实例。

单继承很好理解,方法查找就是沿着继承链一路往上找。但 Python 支持多继承,问题就来了:两个父类有同名方法,到底调谁的?
经典的 菱形继承 问题长这样:
Pythonclass A:
def do(self):
print("A")
class B(A):
def do(self):
print("B")
class C(A):
def do(self):
print("C")
class D(B, C):
pass
d = D()
d.do() # 输出 B
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
D 同时继承了 B 和 C,B 和 C 又都继承了 A,形成一个菱形。Python 用 C3 线性化算法来决定方法解析顺序,核心规则就两条:
1)子类永远排在父类前面 2)如果有多个父类,按照继承列表里的声明顺序来
所以 D 的 MRO 是 D → B → C → A → object,调用 d.do() 找到 B 就停了。
可以通过 ClassName.mro 或 ClassName.mro() 查看任何类的方法解析顺序。如果 C3 算法算不出合法的线性化顺序,Python 会直接抛 TypeError,连类都定义不了。

很多人以为 super() 就是"调用父类的方法",在单继承下确实可以这么理解。但在多继承体系里,super() 调用的其实是 MRO 里的下一个类,不一定是直接父类。
Pythonclass A:
def __init__(self):
print("A init")
super().__init__()
class B(A):
def __init__(self):
print("B init")
super().__init__()
class C(A):
def __init__(self):
print("C init")
super().__init__()
class D(B, C):
def __init__(self):
print("D init")
super().__init__()
D()
# D init → B init → C init → A init
注意 B 的 super().init() 调用的不是 A,是 C,因为 D 的 MRO 是 D → B → C → A。这就是为什么在多继承场景下,每个类的 init 都要调用 super().init(),否则调用链会断掉。
实际项目中很少直接搞复杂的多继承,更常见的做法是用 Mixin。Mixin 类本身不独立使用,只是把一组功能"混入"到目标类里。Django 的 class-based views 就是典型代表:
Pythonclass LogMixin:
def log(self, message):
print(f"[{self.__class__.__name__}] {message}")
class SerializeMixin:
def to_dict(self):
return self.__dict__
class User(LogMixin, SerializeMixin):
def __init__(self, name, age):
self.name = name
self.age = age
u = User("Alice", 30)
u.log("created") # [User] created
print(u.to_dict()) # {'name': 'Alice', 'age': 30}
Mixin 的命名约定是以 Mixin 结尾,一看就知道不是普通的父类。Django 的 LoginRequiredMixin、PermissionRequiredMixin 都是这个套路。
Python 的 abc 模块提供了抽象基类的支持,能强制子类实现指定方法。跟 Java 的 abstract class 思路一样,没实现抽象方法就不让实例化:
Pythonfrom abc import ABC, abstractmethod
class PaymentGateway(ABC):
@abstractmethod
def charge(self, amount):
pass
@abstractmethod
def refund(self, transaction_id):
pass
class StripeGateway(PaymentGateway):
def charge(self, amount):
return f"Stripe charged {amount}"
def refund(self, transaction_id):
return f"Stripe refunded {transaction_id}"
# PaymentGateway() # TypeError: 抽象类不能实例化
gateway = StripeGateway()
print(gateway.charge(100)) # Stripe charged 100
Python 3.3 之后,collections.abc 模块把常用的抽象基类都内置了,像 Iterable、Mapping、Sequence 这些。自定义容器类的时候继承它们,能确保接口的完整性。
isinstance 检查的是整条继承链,不只是直接父类。issubclass 同理:
Pythonprint(isinstance(gateway, StripeGateway)) # True
print(isinstance(gateway, PaymentGateway)) # True
print(isinstance(gateway, ABC)) # True
print(issubclass(StripeGateway, PaymentGateway)) # True
Python 还支持通过 subclasshook 实现虚拟子类,不需要真的继承也能让 isinstance 返回 True,collections.abc 里的 Hashable 就是这么干的。
本文作者:Dewar
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!