第56集:继承基础
学习目标
- 理解继承的概念和作用
- 掌握继承的语法和用法
- 学会使用
super()调用父类方法 - 理解方法查找顺序(MRO)
- 掌握继承中的属性覆盖
- 学会设计合理的继承层次
一、继承概述
1.1 什么是继承
继承:子类可以继承父类的属性和方法,实现代码复用和扩展。
1.2 继承的作用
┌─────────────────────────────────────┐
│ 父类 (Parent) │
│ - 公共属性 │
│ - 公共方法 │
└─────────────────────────────────────┘
↓ 继承
┌─────────────────────────────────────┐
│ 子类 (Child) │
│ - 继承父类的属性和方法 │
│ - 可以添加新的属性和方法 │
│ - 可以重写父类的方法 │
└─────────────────────────────────────┘继承的好处:
- 代码复用
- 建立类之间的关系
- 实现多态
- 提高代码的可维护性
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):
# 子类的属性和方法
pass2.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 常见错误
- 忘记调用父类的__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- 继承过深:
# 继承层次太深,代码难以维护
class A: pass
class B(A): pass
class C(B): pass
class D(C): pass
class E(D): pass
# ...8.2 注意事项
- 合理使用继承:不要为了继承而继承
- 优先使用组合:在某些情况下组合比继承更好
- 重写方法时考虑调用super()
- 避免循环继承
- 设计清晰的继承层次
九、课后练习
练习题
编程题
- 定义一个
Vehicle基类 - 创建
Car和Motorcycle子类 - 实现各自特有的方法
- 定义一个
编程题
- 定义一个
Employee基类 - 创建
Manager和Developer子类 - 重写计算薪资的方法
- 定义一个
思考题
- 什么时候应该使用继承?
- 继承和组合有什么区别?
- 什么是方法解析顺序(MRO)?
十、本集总结
核心知识点回顾
- 继承概念:子类继承父类的属性和方法
- super()函数:调用父类的方法
- 属性覆盖:子类可以覆盖父类的属性和方法
- 继承层次:多层继承和兄弟类
- MRO:方法解析顺序
下集预告
下一集我们将学习方法重写,深入了解如何在子类中重写父类方法。
学习建议: 理解继承的思想,合理设计继承层次。通过实际编程练习,掌握继承的应用场景和技巧。