本章摘要

  1. 核心目标:掌握单继承、super()、方法重写与多继承,能用继承复用代码、用重写定制行为
  2. 核心知识点:单继承语法、super()调用父类、方法重写、多继承、MRO方法解析顺序
  3. 实操产出:动物王国继承体系(Animal基类+Dog/Cat/Bird子类)
  4. 前置基础:第15章类与对象(class定义、__init__、实例方法)

一、写在前面

上一章你学会了定义类、创建对象、写 __init__ 和实例方法。现在设想一个场景:你要写 Dog 类和 Cat 类,它们都有 nameage 属性,都有 eat 方法。如果两个类各写一遍,代码重复,改一个忘改另一个,bug 就来了。

继承就是解决这个问题——子类直接获得父类的属性和方法,不用重写一遍。子类还可以重写(覆盖)父类的方法来定制自己的行为,也可以新增自己的方法。这一章就来学继承的完整用法。


二、什么是继承

一句话说清楚:子类继承父类,自动拥有父类的所有属性和方法,同时可以扩展自己的。

生活类比:父类是"动物",有名字、年龄,能吃东西。子类是"狗",自动拥有动物的一切,还能加自己的——汪汪叫、摇尾巴。

📷 图片占位:inheritance-tree.png — 继承关系树状图(Animal父类→Dog/Cat/Bird子类)

先看一个最简单的例子:

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

    def eat(self):
        print(f"{self.name}在吃东西")

# 子类继承父类(括号里写父类名)
class Dog(Animal):
    pass  # 什么都不写,也能用父类的一切

dog = Dog("旺财")
dog.eat()  # 旺财在吃东西 ← 继承来的,Dog自己没写 eat

Dog(Animal) 中的括号就是继承的标志。Dog 什么都没写(pass),但创建 Dog("旺财") 后,dog.eat() 照样能用——因为 eat 是从 Animal 继承来的。


三、单继承语法

3.1 基本语法

class 子类名(父类名):
    # 子类自己的属性和方法

就这一行语法,记住就好。如果类定义时不写括号(class Dog:),默认继承 Python 的根类 object,所有类最终都继承自 object

3.2 子类拥有父类的一切

子类自动获得父类的属性和方法,不需要重新定义:

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

    def eat(self):
        print(f"{self.name}在吃东西")

    def sleep(self):
        print(f"{self.name}在睡觉")

class Dog(Animal):
    pass

dog = Dog("旺财", 3)
print(dog.name)   # 旺财 ← 父类的属性
print(dog.age)    # 3 ← 父类的属性
dog.eat()         # 旺财在吃东西 ← 父类的方法
dog.sleep()       # 旺财在睡觉 ← 父类的方法

3.3 子类扩展自己的方法

继承不是只能"白拿",子类可以添加父类没有的方法:

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

    def eat(self):
        print(f"{self.name}在吃东西")

class Dog(Animal):
    # Dog 独有的方法
    def bark(self):
        print(f"{self.name}汪汪叫")

    def wag_tail(self):
        print(f"{self.name}摇尾巴")

dog = Dog("旺财")
dog.eat()       # 旺财在吃东西 ← 继承自 Animal
dog.bark()      # 旺财汪汪叫 ← Dog 自己的
dog.wag_tail()  # 旺财摇尾巴 ← Dog 自己的

子类 = 父类的一切 + 自己新增的内容。能用的更多了,不会更少。


四、子类调用父类方法:super()

4.1 为什么需要 super()

当子类需要自己的 __init__ 时(比如 DogAnimal 多一个 breed 属性),会覆盖父类的 __init__。这时父类的属性就不会被初始化了:

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

class Dog(Animal):
    def __init__(self, name, age, breed):
        # ❌ 忘记调用 super().__init__(),父类属性没有初始化
        self.breed = breed

dog = Dog("旺财", 3, "金毛")
print(dog.breed)  # 金毛 ← 子类属性正常
print(dog.name)   # ❌ AttributeError: 'Dog' object has no attribute 'name'

子类定义了 __init__,就把父类的 __init__ 覆盖了。self.nameself.age 根本没被赋值,访问就报错。解决办法就是用 super() 调用父类的 __init__

4.2 super() 调用父类 __init__

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

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # ✅ 调用父类 __init__,初始化 name 和 age
        self.breed = breed           # 子类自己的属性

dog = Dog("旺财", 3, "金毛")
print(dog.name)   # 旺财 ← 父类初始化的
print(dog.age)    # 3 ← 父类初始化的
print(dog.breed)  # 金毛 ← 子类自己的

📷 图片占位:super-call-flow.png — super()调用流程图(子类方法→super()→父类方法→返回子类继续)

super().__init__(name, age) 的意思是:先让父类把 nameage 初始化好,子类再添加自己的 breed。执行顺序是"父类先,子类后"。

4.3 super() 调用父类普通方法

super() 不限于 __init__,父类的任何方法都可以用 super() 调用:

class Animal:
    def eat(self):
        print(f"{self.name}在吃东西")

class Dog(Animal):
    def eat(self):
        super().eat()  # 先执行父类的 eat
        print(f"{self.name}吃完了,舔了舔嘴巴")  # 再添加自己的行为

dog = Dog("旺财", 3, "金毛")
dog.eat()
# 旺财在吃东西
# 旺财吃完了,舔了舔嘴巴

super() 的本质:在子类方法中,"顺便"调用一下父类的同名方法。父类的逻辑先跑,子类的逻辑接着跑,两者都不丢。


五、方法重写

5.1 重写父类方法

方法重写(Override):子类中定义一个与父类同名的方法,调用时执行子类的版本,父类的被覆盖。

class Animal:
    def speak(self):
        print("动物发出声音")

class Dog(Animal):
    def speak(self):
        print("汪汪汪!")  # 重写:覆盖父类的 speak

class Cat(Animal):
    def speak(self):
        print("喵喵喵!")  # 重写:覆盖父类的 speak

dog = Dog()
cat = Cat()
dog.speak()  # 汪汪汪!← 执行 Dog 的版本
cat.speak()  # 喵喵喵!← 执行 Cat 的版本

同一个 speak() 方法,Dog 对象调用就汪汪叫,Cat 对象调用就喵喵叫——这就是多态的雏形:同样的方法名,不同对象有不同的行为。

5.2 重写后保留父类行为

重写不意味着"丢弃"父类的代码。用 super() 可以在重写的同时保留父类的逻辑:

class Animal:
    def speak(self):
        print("动物发出声音")

class Dog(Animal):
    def speak(self):
        super().speak()  # 先调用父类版本
        print("汪汪汪!")  # 再添加自己的内容

dog = Dog()
dog.speak()
# 动物发出声音
# 汪汪汪!

记住两个选择:完全重写(不调 super,只写自己的逻辑)或扩展重写(先 super 调父类,再添加自己的逻辑)。根据需求选。


六、多继承基础

6.1 多继承语法

Python 支持一个子类继承多个父类,语法是在括号里写多个父类,用逗号分隔:

class Flyable:
    def fly(self):
        print("正在飞行")

class Swimmable:
    def swim(self):
        print("正在游泳")

class Duck(Flyable, Swimmable):
    pass

duck = Duck()
duck.fly()   # 正在飞行 ← 来自 Flyable
duck.swim()  # 正在游泳 ← 来自 Swimmable

Duck 同时继承了 FlyableSwimmable,既有 fly 方法又有 swim 方法。

6.2 同名方法的查找顺序

如果多个父类有同名方法,Python 按从左到右的顺序查找:

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

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

class C(A, B):
    pass

c = C()
c.hello()  # A 的 hello ← A 写在前面,优先找到

多继承时父类顺序很重要:class C(A, B)class C(B, A) 结果可能不同。具体查找顺序由 MRO 决定,下一节讲。


七、MRO 概念简述

MROMethod Resolution Order,方法解析顺序)决定了 Python 在继承链中按什么顺序查找方法。Python 使用 C3 线性化算法,保证每个类只被访问一次。

类名.__mro__类名.mro() 可以查看查找顺序:

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

class B(A):
    pass

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

class D(B, C):
    pass

d = D()
d.hello()  # C ← MRO: D → B → C → A

print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

查找过程:D 没有 hello → 找 B(没有)→ 找 C(有!执行 C 的 hello)→ 不再继续找 A。

这就是经典的钻石继承(菱形继承):

    A
   / \
  B   C
   \ /
    D

B 和 C 都继承 A,D 同时继承 B 和 C,形状像钻石。Python 的 MRO 保证 A 只在最后被访问一次,不会重复执行。

新手阶段了解 MRO 的概念即可,知道用 __mro__ 查看顺序就行。实际开发中遇到多继承的复杂问题再深入。


八、Scratch 积木对照

Scratch Python 说明
克隆体继承母体属性 class Dog(Animal): Scratch 克隆体自带母体属性,Python 子类自带父类属性和方法

在这里插入图片描述

# Scratch「克隆体继承母体属性」→ Python 对照
# Scratch: 克隆出来的角色自带母体的变量值
# Python: 子类自动拥有父类的属性和方法
class Animal:
    def __init__(self, name):
        self.name = name

class Dog(Animal):  # Dog 继承 Animal,自带 name 属性
    pass

dog = Dog("旺财")
print(dog.name)  # 旺财 ← 继承来的

Scratch 中克隆体出生时就带着母体的变量值,不需要重新设置。Python 的继承也是类似的——子类创建对象时,父类的属性和方法自动就位,不用重新写。


九、综合实战:动物王国继承体系

综合运用类定义、继承、super()、方法重写、多态基础,搭建一个完整的动物继承体系。

# ========================================
# 动物王国继承体系
# ========================================

# 基类:动物
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

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

    def info(self):
        print(f"我是{self.name},今年{self.age}岁")

# 子类:狗(重写 speak + 重写 info)
class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用父类初始化 name 和 age
        self.breed = breed           # 子类新增属性

    def speak(self):
        print(f"{self.name}说:汪汪汪!")  # 重写 speak

    def info(self):
        super().info()              # 先调用父类 info
        print(f"品种:{self.breed}")  # 再补充自己的信息

# 子类:猫(只重写 speak)
class Cat(Animal):
    def speak(self):
        print(f"{self.name}说:喵喵喵!")  # 重写 speak

# 子类:鸟(重写 speak + 新增 fly)
class Bird(Animal):
    def __init__(self, name, age, wing_length):
        super().__init__(name, age)
        self.wing_length = wing_length

    def speak(self):
        print(f"{self.name}说:叽叽喳喳!")

    def fly(self):
        print(f"{self.name}展翅飞翔,翼展{self.wing_length}厘米")

# ========== 展示继承与多态 ==========

print("=" * 40)
print("      动物王国继承体系演示")
print("=" * 40)

# 创建不同动物,放进同一个列表
animals = [
    Dog("旺财", 3, "金毛"),
    Cat("咪咪", 2),
    Bird("小蓝", 1, 15),
]

# 遍历所有动物,统一调用 speak —— 多态的体现
for animal in animals:
    animal.info()
    animal.speak()
    # 鸟可以飞,其他动物没有 fly 方法
    if isinstance(animal, Bird):
        animal.fly()
    print("-" * 30)

运行结果:

========================================
      动物王国继承体系演示
========================================
我是旺财,今年3岁
品种:金毛
旺财说:汪汪汪!
------------------------------
我是咪咪,今年2岁
咪咪说:喵喵喵!
------------------------------
我是小蓝,今年1岁
小蓝说:叽叽喳喳!
小蓝展翅飞翔,翼展15厘米
------------------------------

注意:旺财是狗,不会飞,所以没有调用 fly()isinstance(animal, Bird) 判断旺财不是 Bird,跳过了 fly 调用。只有小蓝是 Bird,才执行了 fly()。这就是 isinstance 做类型判断的用处。

分步拆解:

  1. Animal 基类:定义了 nameage 两个属性,speak()info() 两个方法。所有子类都能继承这些
  2. Dog 子类:通过 super().__init__(name, age) 初始化父类属性,新增 breed 属性。重写了 speak()(输出汪汪)和 info()(先调 super 保留父类信息,再补充品种)
  3. Cat 子类:不需要新增属性,所以不写 __init__,自动用父类的。只重写了 speak()(输出喵喵)
  4. Bird 子类:新增 wing_length 属性,重写 speak(),还新增了 fly() 方法——这是父类没有的
  5. 多态演示:把 DogCatBird 放进同一个列表,循环调用 animal.speak()。同样的方法调用,不同对象表现出不同行为——这就是多态。用 isinstance(animal, Bird) 判断是否是鸟,是鸟才调 fly()

十、常见报错速查表

报错信息 出现场景 原因 解决方法
AttributeError: 'Dog' object has no attribute 'name' 子类访问父类属性 子类 __init__ 没调用 super().__init__(),父类属性未初始化 在子类 __init__ 中添加 super().__init__(name, age)
TypeError: __init__() missing 2 required positional arguments 创建对象时 传参数量与 __init__ 定义不匹配 检查 __init__ 参数列表,传入所有必需参数
TypeError: Cannot create a consistent method resolution order (MRO) 多继承时 继承顺序矛盾,如 class C(A, B) 但 B 继承了 A 调整继承顺序,确保父类顺序合理
AttributeError: 'super' object has no attribute 'fly' super() 调用方法时 父类中没有定义该方法 确认父类确实有该方法,检查方法名拼写
TypeError: speak() takes 0 positional arguments but 1 was given 调用实例方法时 方法定义忘记写 self 参数 实例方法第一个参数必须是 self
NameError: name 'Animal' is not defined 定义子类时 父类在子类之后定义,或父类名拼写错误 确保父类在子类之前定义,检查类名拼写

十二、本章小结

本章你掌握了 Python 继承的完整用法:

  1. 单继承——class 子类(父类):,子类自动拥有父类的属性和方法,还能扩展自己的
  2. super()——super().__init__() 调用父类初始化,super().方法名() 调用父类普通方法
  3. 方法重写——子类定义与父类同名的方法,覆盖父类行为;可用 super() 保留父类逻辑
  4. 多继承——class C(A, B):,一个子类继承多个父类,按 MRO 顺序查找方法
  5. MRO——方法解析顺序,用 类名.__mro__ 查看,保证每个类只访问一次

继承让代码复用变得简单,重写让定制行为变得灵活,多态让同一接口应对不同对象。

往期回顾:

《Python 零基础入门:从积木到代码》专栏序

零基础学 Python 第1章 | 全平台装环境 + VS Code 配置 + 第一个 Hello World

零基础学 Python 第2章 | print 输出 + 变量赋值 + input 交互输入

零基础学 Python 第3章 | 条件判断:if / elif / else

零基础学 Python 第 4 章 | for 循环与 range():让程序帮你重复干活

零基础学 Python 第 5 章 | while 循环与循环嵌套:让程序看着条件自己干活

零基础学 Python 第 6 章 | 元组与集合:不可变数据与自动去重

零基础学 Python 第7章 | 字典 dict:键值对存储

零基础学 Python 第8章 | 字符串操作与格式化输出

零基础学 Python 第9章 | 函数基础:def、参数与返回值

零基础学 Python 第10章 | 函数进阶:参数灵活用法与作用域

零基础学 Python 第11章 | 匿名函数与高阶函数

零基础学 Python 第12章 | 文件读写:让数据持久保存

零基础学 Python 第13章 | 异常处理:try-except 让程序不崩溃

零基础学 Python 第14章 | 模块、包与第三方库

零基础学 Python 第15章 | 类与对象:面向对象编程入门

下一章预告:到目前为止,类的属性都是公开的,谁都能改。下一章学习封装与 property——用私有属性保护数据,用 property 控制属性的读写,让代码更安全、更专业。


文末资源区

资源 说明
Python 官方文档 - 继承 https://docs.python.org/3/tutorial/classes.html#inheritance
Python 官方文档 - super() https://docs.python.org/3/library/functions.html#super
Python 官方文档 - 多继承与 MRO https://docs.python.org/3/howto/mro.html
本章完整源码 chapter16_all.py(关注梅雅达编程笔记,评论领资料)

每节课都配套课后练习题与完整源码。代码报错、看不懂知识点,可在评论区粘贴问题,逐一解答!
欢迎关注梅雅达编程笔记,持续分享Python零基础学习内容

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐