类的继承

深入理解 Python 类的继承机制,包括单继承、多继承、方法重写、super()函数的使用以及继承中的初始化过程

分类: Python 基础 难度: 中级
面向对象 继承 多态 方法重写

类的继承

概述

继承是面向对象编程的三大特性之一,它允许一个类(子类)从另一个类(父类)获取属性和方法。通过继承,我们可以实现代码复用,建立类之间的层次关系,并支持多态性。Python 支持单继承和多继承,为面向对象设计提供了强大的工具。

学习目标

通过本章学习,你将能够:

  • 理解继承的基本概念和语法
  • 掌握方法重写和 super()函数的使用
  • 了解继承中的初始化过程
  • 理解访问控制在继承中的表现
  • 掌握多继承的概念和方法解析顺序(MRO)
  • 能够设计合理的类继承结构

前置知识

  • Python 类的定义和基本使用
  • 实例属性和类属性的区别
  • 方法的定义和调用
  • 面向对象编程基础概念

详细内容

基本概念

继承允许子类从父类获取特征(属性和方法),实现代码复用和层次化设计。

基本语法

class 子类名(父类名):
#    # 子类的定义
    pass

## 多继承语法
class 子类名(父类 1, 父类 2, ...):
#    # 子类的定义
    pass

简单继承示例

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} 发出声音")
    
    def move(self):
        print(f"{self.name} 在移动")

class Dog(Animal):
    def speak(self):
        print(f"{self.name} 汪汪叫")

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

## 使用示例
dog = Dog("小黑")
cat = Cat("小白")

dog.speak()  # 小黑 汪汪叫
dog.move()   # 小黑 在移动
cat.speak()  # 小白 喵喵叫
cat.move()   # 小白 在移动

继承中的访问控制

在继承关系中,访问控制规则依然有效:

class Parent:
    def __init__(self):
        self.public_attr = "公有属性"
        self._protected_attr = "受保护属性"
        self.__private_attr = "私有属性"
    
    def public_method(self):
        return "公有方法"
    
    def _protected_method(self):
        return "受保护方法"
    
    def __private_method(self):
        return "私有方法"
    
    def access_private(self):
        return self.__private_method()  # 类内部可以访问私有方法

class Child(Parent):
    def test_access(self):
        print(self.public_attr)        # ✓ 可以访问
        print(self._protected_attr)    # ✓ 可以访问
#        # print(self.__private_attr)   # ✗ 不能直接访问
        
        self.public_method()            # ✓ 可以调用
        self._protected_method()        # ✓ 可以调用
#        # self.__private_method()       # ✗ 不能直接调用
        
#        # 通过父类的公有方法间接访问私有成员
        print(self.access_private())    # ✓ 可以调用

## 使用示例
child = Child()
child.test_access()

方法重写

子类可以重写父类的方法,提供自己的实现:

class Vehicle:
    def __init__(self, brand):
        self.brand = brand
    
    def start(self):
        print(f"{self.brand} 启动了")
    
    def stop(self):
        print(f"{self.brand} 停止了")

class Car(Vehicle):
    def start(self):
        print(f"{self.brand} 汽车点火启动")
        print("检查安全带")
        print("启动引擎")

class Bicycle(Vehicle):
    def start(self):
        print(f"{self.brand} 自行车开始骑行")
        print("踩踏板")

## 使用示例
car = Car("奔驰")
bike = Bicycle("捷安特")

car.start()   # 重写的方法
car.stop()    # 继承的方法
bike.start()  # 重写的方法

super()函数的使用

super()函数用于调用父类的方法,特别是在方法重写时:

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def introduce(self):
        print(f"我是 {self.name},{self.age} 岁")

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用父类的__init__
        self.breed = breed
    
    def introduce(self):
        super().introduce()  # 调用父类的 introduce 方法
        print(f"我是 {self.breed} 品种的狗")
    
    def bark(self):
        print(f"{self.name} 在汪汪叫")

## 使用示例
dog = Dog("旺财", 3, "金毛")
dog.introduce()
## 输出:
## 我是 旺财,3 岁
## 我是 金毛 品种的狗

继承中的初始化

理解继承中的初始化过程非常重要:

class Parent:
    def __init__(self, value):
        self.parent_value = value
        print(f"Parent 初始化: {value}")

class Child(Parent):
    def __init__(self, value, child_value):
        super().__init__(value)  # 必须显式调用父类的__init__
        self.child_value = child_value
        print(f"Child 初始化: {child_value}")

## 正确的初始化
child = Child("父类值", "子类值")
print(child.parent_value)  # 父类值
print(child.child_value)   # 子类值

如果子类没有定义__init__方法,会自动调用父类的__init__

class Parent:
    def __init__(self):
        self.value = "来自父类"
        print("父类初始化")

class Child(Parent):
    pass  # 没有定义__init__

## 会自动调用父类的__init__
child = Child()  # 输出: 父类初始化
print(child.value)  # 来自父类

多继承

Python 支持多继承,但需要注意方法解析顺序(MRO):

class Flyable:
    def fly(self):
        print("我可以飞行")

class Swimmable:
    def swim(self):
        print("我可以游泳")

class Duck(Animal, Flyable, Swimmable):
    def __init__(self, name):
        super().__init__(name)
    
    def speak(self):
        print(f"{self.name} 嘎嘎叫")

## 使用示例
duck = Duck("唐老鸭")
duck.speak()  # 唐老鸭 嘎嘎叫
duck.fly()    # 我可以飞行
duck.swim()   # 我可以游泳
duck.move()   # 唐老鸭 在移动(继承自 Animal)

## 查看方法解析顺序
print(Duck.__mro__)
## (<class '__main__.Duck'>, <class '__main__.Animal'>, 
##  <class '__main__.Flyable'>, <class '__main__.Swimmable'>, 
##  <class 'object'>)

继承相关的特殊属性

class A:
    pass

class B(A):
    pass

class C(B):
    pass

## 查看继承关系
print(C.__bases__)      # 直接父类: (<class '__main__.B'>,)
print(C.__mro__)        # 方法解析顺序
print(C.mro())          # 同上
print(A.__subclasses__()) # A 的子类: [<class '__main__.B'>]

## 实例检查
c = C()
print(isinstance(c, C))  # True
print(isinstance(c, B))  # True
print(isinstance(c, A))  # True
print(issubclass(C, A))  # True

实际应用案例

案例 1:员工管理系统

class Employee:
    """员工基类"""
    def __init__(self, name, employee_id, salary):
        self.name = name
        self.employee_id = employee_id
        self.salary = salary
    
    def get_info(self):
        return f"员工: {self.name}, ID: {self.employee_id}, 薪资: {self.salary}"
    
    def calculate_bonus(self):
        return self.salary * 0.1  # 基础奖金 10%

class Manager(Employee):
    """经理类"""
    def __init__(self, name, employee_id, salary, team_size):
        super().__init__(name, employee_id, salary)
        self.team_size = team_size
    
    def calculate_bonus(self):
        base_bonus = super().calculate_bonus()
        team_bonus = self.team_size * 1000  # 每个团队成员 1000 奖金
        return base_bonus + team_bonus
    
    def get_info(self):
        base_info = super().get_info()
        return f"{base_info}, 团队规模: {self.team_size}"

class Developer(Employee):
    """开发者类"""
    def __init__(self, name, employee_id, salary, programming_languages):
        super().__init__(name, employee_id, salary)
        self.programming_languages = programming_languages
    
    def calculate_bonus(self):
        base_bonus = super().calculate_bonus()
        skill_bonus = len(self.programming_languages) * 500  # 每种语言 500 奖金
        return base_bonus + skill_bonus
    
    def get_info(self):
        base_info = super().get_info()
        languages = ", ".join(self.programming_languages)
        return f"{base_info}, 技能: {languages}"

## 使用示例
manager = Manager("张三", "M001", 15000, 5)
developer = Developer("李四", "D001", 12000, ["Python", "Java", "JavaScript"])

print(manager.get_info())
print(f"经理奖金: {manager.calculate_bonus()}")
print()
print(developer.get_info())
print(f"开发者奖金: {developer.calculate_bonus()}")

案例 2:图形绘制系统

import math

class Shape:
    """图形基类"""
    def __init__(self, color="black"):
        self.color = color
    
    def area(self):
        raise NotImplementedError("子类必须实现 area 方法")
    
    def perimeter(self):
        raise NotImplementedError("子类必须实现 perimeter 方法")
    
    def describe(self):
        return f"这是一个{self.color}色的图形"

class Circle(Shape):
    """圆形类"""
    def __init__(self, radius, color="black"):
        super().__init__(color)
        self.radius = radius
    
    def area(self):
        return math.pi * self.radius ** 2
    
    def perimeter(self):
        return 2 * math.pi * self.radius
    
    def describe(self):
        base_desc = super().describe()
        return f"{base_desc},半径为{self.radius}的圆形"

class Rectangle(Shape):
    """矩形类"""
    def __init__(self, width, height, color="black"):
        super().__init__(color)
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)
    
    def describe(self):
        base_desc = super().describe()
        return f"{base_desc},宽{self.width}{self.height}的矩形"

class Square(Rectangle):
    """正方形类(继承自矩形)"""
    def __init__(self, side, color="black"):
        super().__init__(side, side, color)  # 正方形的宽高相等
        self.side = side
    
    def describe(self):
        return f"这是一个{self.color}色的,边长为{self.side}的正方形"

## 使用示例
shapes = [
    Circle(5, "红"),
    Rectangle(4, 6, "蓝"),
    Square(3, "绿")
]

for shape in shapes:
    print(shape.describe())
    print(f"面积: {shape.area():.2f}")
    print(f"周长: {shape.perimeter():.2f}")
    print("-" * 30)

注意事项

  1. 合理使用继承:继承应该表示”是一个”的关系,而不是”有一个”的关系
  2. 避免过深的继承层次:过深的继承会增加代码复杂性
  3. 谨慎使用多继承:多继承可能导致钻石问题,需要理解 MRO
  4. 正确调用父类初始化:在子类的__init__中记得调用super().__init__()
  5. 遵循里氏替换原则:子类对象应该能够替换父类对象而不影响程序正确性

相关内容

扩展阅读

  • Python 官方文档:类的继承
  • 《Effective Python》中关于继承的最佳实践
  • 面向对象设计原则(SOLID 原则)
  • 组合 vs 继承的选择策略

🧭 继承关系示例:Circle 继承 Point

下面是一个简洁的继承示例,展示如何让 Circle 继承自 Point,并进行类型关系检查:

# 基类:点
class Point:
    """二维坐标点"""
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def move(self, dx: float, dy: float):
        """移动点的位置"""
        self.x += dx
        self.y += dy

# 子类:圆
class Circle(Point):
    """圆形,继承自Point"""
    def __init__(self, x: float, y: float, radius: float):
        super().__init__(x, y)  # 复用父类初始化
        self.radius = radius

    def area(self) -> float:
        """计算圆面积"""
        from math import pi
        return pi * (self.radius ** 2)

# 使用示例
c = Circle(0, 0, 2)
print(c.x, c.y, c.radius)       # 0 0 2
print(round(c.area(), 2))       # 12.57

# 类型关系检查
print(isinstance(c, Circle))    # True
print(isinstance(c, Point))     # True (子类实例也是父类实例)
print(issubclass(Circle, Point))# True
print(issubclass(Point, Circle))# False

要点:

  • 子类通过 super() 调用父类构造函数,避免重复代码
  • 子类拥有父类的属性/方法,并可新增专有能力(如 area)
  • isinstance 检查对象是否为类或其子类的实例;issubclass 检查类之间的继承关系

作者: Python 教程

版本: 1.0

讨论与反馈

欢迎在下方留言讨论,分享你的学习心得或提出问题。评论基于GitHub Issues,需要GitHub账号。