第56集:继承基础

学习目标

  • 理解继承的概念和作用
  • 掌握继承的语法和用法
  • 学会使用super()调用父类方法
  • 理解方法查找顺序(MRO)
  • 掌握继承中的属性覆盖
  • 学会设计合理的继承层次

一、继承概述

1.1 什么是继承

继承:子类可以继承父类的属性和方法,实现代码复用和扩展。

1.2 继承的作用

┌─────────────────────────────────────┐
│          父类 (Parent)              │
│  - 公共属性                          │
│  - 公共方法                          │
└─────────────────────────────────────┘
              ↓ 继承
┌─────────────────────────────────────┐
│          子类 (Child)               │
│  - 继承父类的属性和方法               │
│  - 可以添加新的属性和方法             │
│  - 可以重写父类的方法                 │
└─────────────────────────────────────┘

继承的好处:

  1. 代码复用
  2. 建立类之间的关系
  3. 实现多态
  4. 提高代码的可维护性

1.3 继承示例

# 父类
class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        print(f"{self.name}在吃东西")
    
    def sleep(self):
        print(f"{self.name}在睡觉")

# 子类继承父类
class Dog(Animal):
    def bark(self):
        print(f"{self.name}汪汪叫")

# 创建子类对象
dog = Dog("小黑")
dog.eat()    # 继承的方法
dog.sleep()  # 继承的方法
dog.bark()   # 子类自己的方法

二、继承的语法

2.1 基本语法

class ParentClass:
    # 父类的属性和方法
    pass

class ChildClass(ParentClass):
    # 子类的属性和方法
    pass

2.2 单继承

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

class Car(Vehicle):
    def __init__(self, brand, color, model):
        super().__init__(brand, color)  # 调用父类的__init__
        self.model = model

car = Car("Toyota", "白色", "Camry")
car.start()
car.stop()

2.3 方法继承

class Parent:
    def method1(self):
        print("父类方法1")
    
    def method2(self):
        print("父类方法2")

class Child(Parent):
    def method3(self):
        print("子类方法3")

c = Child()
c.method1()  # 继承的方法
c.method2()  # 继承的方法
c.method3()  # 子类自己的方法

三、super()函数

3.1 super()的作用

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

3.2 基本用法

class Parent:
    def __init__(self, name):
        self.name = name
    
    def greet(self):
        print(f"我是{self.name}")

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)  # 调用父类的__init__
        self.age = age
    
    def greet(self):
        super().greet()  # 调用父类的greet
        print(f"今年{self.age}岁")

c = Child("张三", 18)
c.greet()
# 输出:
# 我是张三
# 今年18岁

3.3 在重写方法中使用super()

class Animal:
    def __init__(self, name):
        self.name = name
        self.health = 100
    
    def eat(self):
        print(f"{self.name}吃东西,恢复10点生命")
        self.health += 10

class Dog(Animal):
    def eat(self):
        print(f"{self.name}吃狗粮,美味!")
        super().eat()  # 调用父类的eat方法

dog = Dog("小黑")
dog.eat()
print(f"生命值: {dog.health}")
# 输出:
# 小黑吃狗粮,美味!
# 小黑吃东西,恢复10点生命
# 生命值: 110

四、属性覆盖

4.1 覆盖父类属性

class Parent:
    value = "父类的值"
    
    def __init__(self):
        self.name = "父类名称"

class Child(Parent):
    value = "子类的值"  # 覆盖父类属性
    
    def __init__(self):
        super().__init__()
        self.name = "子类名称"  # 覆盖实例属性

print(Parent.value)  # 输出:父类的值
print(Child.value)   # 输出:子类的值

c = Child()
print(c.name)  # 输出:子类名称

4.2 方法覆盖

class Parent:
    def method(self):
        print("父类方法")

class Child(Parent):
    def method(self):  # 覆盖父类方法
        print("子类方法")

c = Child()
c.method()  # 输出:子类方法

4.3 扩展父类方法

class Parent:
    def greet(self):
        print("你好!")

class Child(Parent):
    def greet(self):
        super().greet()  # 先调用父类方法
        print("很高兴认识你!")  # 再添加自己的逻辑

c = Child()
c.greet()
# 输出:
# 你好!
# 很高兴认识你!

五、继承层次

5.1 多层继承

class GrandParent:
    def grand_method(self):
        print("祖类方法")

class Parent(GrandParent):
    def parent_method(self):
        print("父类方法")

class Child(Parent):
    def child_method(self):
        print("子类方法")

c = Child()
c.grand_method()  # 继承自GrandParent
c.parent_method() # 继承自Parent
c.child_method()  # 自己的方法

5.2 兄弟类

class Parent:
    def parent_method(self):
        print("父类方法")

class Child1(Parent):
    def child1_method(self):
        print("子类1方法")

class Child2(Parent):
    def child2_method(self):
        print("子类2方法")

c1 = Child1()
c2 = Child2()

c1.parent_method()  # 两个子类都继承了父类方法
c2.parent_method()

六、方法解析顺序(MRO)

6.1 MRO概述

MRO(Method Resolution Order):方法查找顺序,Python使用C3算法确定方法的查找顺序。

6.2 查看MRO

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

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

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

class D(B, C):
    pass

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

d = D()
d.method()  # 输出:B(按MRO顺序查找)

6.3 MRO示例

class A:
    def method(self):
        print("A的方法")

class B(A):
    pass

class C(A):
    def method(self):
        print("C的方法")

class D(B, C):
    pass

d = D()
d.method()  # 输出:C的方法
# 查找顺序:D -> B -> C -> A

七、完整示例

7.1 动物类继承体系

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}在睡觉")
    
    def make_sound(self):
        print(f"{self.name}发出声音")

class Dog(Animal):
    """狗类"""
    
    def __init__(self, name, age, breed):
        super().__init__(name, age)
        self.breed = breed
    
    def make_sound(self):
        """重写父类方法"""
        print(f"{self.name}汪汪叫")
    
    def fetch_ball(self):
        print(f"{self.name}去捡球")

class Cat(Animal):
    """猫类"""
    
    def __init__(self, name, age, color):
        super().__init__(name, age)
        self.color = color
    
    def make_sound(self):
        """重写父类方法"""
        print(f"{self.name}喵喵叫")
    
    def climb_tree(self):
        print(f"{self.name}爬树")

# 使用
dog = Dog("小黑", 3, "金毛")
cat = Cat("小白", 2, "白色")

dog.eat()
dog.make_sound()
dog.fetch_ball()

cat.eat()
cat.make_sound()
cat.climb_tree()

7.2 形状类继承体系

import math

class Shape:
    """形状基类"""
    
    def __init__(self, color):
        self.color = color
    
    def area(self):
        """计算面积"""
        raise NotImplementedError("子类必须实现此方法")
    
    def perimeter(self):
        """计算周长"""
        raise NotImplementedError("子类必须实现此方法")
    
    def describe(self):
        """描述形状"""
        print(f"这是一个{self.color}的形状")

class Circle(Shape):
    """圆形"""
    
    def __init__(self, color, radius):
        super().__init__(color)
        self.radius = radius
    
    def area(self):
        return math.pi * self.radius ** 2
    
    def perimeter(self):
        return 2 * math.pi * self.radius

class Rectangle(Shape):
    """矩形"""
    
    def __init__(self, color, width, height):
        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)

# 使用
circle = Circle("红色", 5)
circle.describe()
print(f"面积: {circle.area():.2f}")
print(f"周长: {circle.perimeter():.2f}")

rectangle = Rectangle("蓝色", 4, 6)
rectangle.describe()
print(f"面积: {rectangle.area()}")
print(f"周长: {rectangle.perimeter()}")

八、常见错误与注意事项

8.1 常见错误

  1. 忘记调用父类的__init__:
class Parent:
    def __init__(self, name):
        self.name = name

class Child(Parent):
    def __init__(self, name, age):
        # 忘记调用super().__init__(name)
        self.age = age

c = Child("张三", 18)
# print(c.name)  # 错误:AttributeError
  1. 继承过深:
# 继承层次太深,代码难以维护
class A: pass
class B(A): pass
class C(B): pass
class D(C): pass
class E(D): pass
# ...

8.2 注意事项

  1. 合理使用继承:不要为了继承而继承
  2. 优先使用组合:在某些情况下组合比继承更好
  3. 重写方法时考虑调用super()
  4. 避免循环继承
  5. 设计清晰的继承层次

九、课后练习

练习题

  1. 编程题

    • 定义一个Vehicle基类
    • 创建CarMotorcycle子类
    • 实现各自特有的方法
  2. 编程题

    • 定义一个Employee基类
    • 创建ManagerDeveloper子类
    • 重写计算薪资的方法
  3. 思考题

    • 什么时候应该使用继承?
    • 继承和组合有什么区别?
    • 什么是方法解析顺序(MRO)?

十、本集总结

核心知识点回顾

  1. 继承概念:子类继承父类的属性和方法
  2. super()函数:调用父类的方法
  3. 属性覆盖:子类可以覆盖父类的属性和方法
  4. 继承层次:多层继承和兄弟类
  5. MRO:方法解析顺序

下集预告

下一集我们将学习方法重写,深入了解如何在子类中重写父类方法。


学习建议: 理解继承的思想,合理设计继承层次。通过实际编程练习,掌握继承的应用场景和技巧。

« 上一篇 封装特性 下一篇 » 方法重写