目 录CONTENT

文章目录

Python(二十九) 类的继承详解

Python(二十九) 类的继承详解

1. 什么是继承

继承是 Python 面向对象编程中的重要概念。

通俗地说:

继承就是一个类可以直接使用另一个类中已经写好的代码。

被继承的类,叫做父类,也叫基类。

继承别人的类,叫做子类,也叫派生类。

例如:

动物是父类。
狗是子类。
猫是子类。

因为狗和猫都是动物,所以它们可以继承动物的共同特点。

动物通常有:

名字
年龄
吃东西
睡觉

狗除了有动物的共同特点,还可以有自己的特点:

汪汪叫
看门

猫也有自己的特点:

喵喵叫
抓老鼠

继承的作用就是:

把公共代码写在父类中。
子类直接复用父类代码。
子类还可以扩展自己的新功能。

2. 为什么需要继承

先看一个没有继承的例子。

class Dog:
    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 bark(self):
        print(f"{self.name}正在汪汪叫")


class Cat:
    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 catch_mouse(self):
        print(f"{self.name}正在抓老鼠")

这段代码中,DogCat 都有:

name
age
eat()
sleep()

这些代码重复了。

如果以后想修改 eat() 方法,就要在多个类里修改,非常麻烦。

使用继承后,可以把公共内容放到父类 Animal 中。

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):
    def bark(self):
        print(f"{self.name}正在汪汪叫")


class Cat(Animal):
    def catch_mouse(self):
        print(f"{self.name}正在抓老鼠")

这样:

Animal 保存公共代码。
Dog 继承 Animal,只写狗特有的功能。
Cat 继承 Animal,只写猫特有的功能。

继承可以减少重复代码,让类之间的关系更清晰。

3. 继承的基本语法

语法:

class 子类名(父类名):
    子类中的代码

示例:

class Animal:
    def eat(self):
        print("动物正在吃东西")


class Dog(Animal):
    pass


dog = Dog()
dog.eat()

输出:

动物正在吃东西

虽然 Dog 类中没有写 eat() 方法,但是它继承了 Animal 类,所以可以直接使用父类中的 eat() 方法。

这里:

Animal 是父类。
Dog 是子类。
Dog 继承 Animal。

4. 父类和子类

在继承关系中:

父类:被继承的类。
子类:继承父类的类。

示例:

class Person:
    def say_hello(self):
        print("你好")


class Student(Person):
    pass

这里:

Person 是父类。
Student 是子类。
Student 继承了 Person。

创建子类对象:

stu = Student()
stu.say_hello()

输出:

你好

子类对象可以调用父类中的方法。

5. 子类可以继承父类的方法

示例:

class Animal:
    def eat(self):
        print("正在吃东西")

    def sleep(self):
        print("正在睡觉")


class Dog(Animal):
    pass


dog = Dog()
dog.eat()
dog.sleep()

输出:

正在吃东西
正在睡觉

Dog 类里没有写 eat()sleep(),但它继承了 Animal,所以可以使用这两个方法。

通俗理解:

父类会的,子类默认也会。

6. 子类可以继承父类的属性

严格来说,属性通常是在 __init__() 方法中创建的。

如果子类继承了父类的 __init__(),就可以拥有父类初始化出来的属性。

示例:

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 类没有写 __init__(),所以会使用父类 Animal__init__()

执行:

dog = Dog("小黑")

相当于给这个狗对象设置了:

self.name = "小黑"

所以后面可以使用:

self.name

7. 子类可以添加自己的方法

子类除了继承父类已有功能,还可以添加自己的新功能。

示例:

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

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


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


dog = Dog("小黑")
dog.eat()
dog.bark()

输出:

小黑正在吃东西
小黑正在汪汪叫

这里:

eat() 是从父类继承来的方法。
bark() 是子类 Dog 自己新增的方法。

这就是继承的常见用法:

父类写通用功能。
子类写特殊功能。

8. 子类可以添加自己的属性

如果子类需要更多属性,可以自己定义 __init__()

但是要注意:如果子类重新写了 __init__(),默认就不会自动执行父类的 __init__()

先看一个容易出错的例子。

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

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


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


dog = Dog("小黑", "黑色")
dog.eat()

这段代码会报错。

原因是:

Dog 自己写了 __init__()。
父类 Animal 的 __init__() 没有自动执行。
所以 dog 对象没有 name 属性。

正确做法是使用 super() 调用父类的 __init__()

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

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


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

    def show_info(self):
        print(f"名字:{self.name},颜色:{self.color}")


dog = Dog("小黑", "黑色")
dog.eat()
dog.show_info()

输出:

小黑正在吃东西
名字:小黑,颜色:黑色

9. super() 是什么

super() 用来调用父类中的方法。

最常见的用法是在子类的 __init__() 中调用父类的 __init__()

示例:

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


class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name, age)
        self.score = score

    def show_info(self):
        print(f"{self.name},{self.age}岁,成绩:{self.score}")


stu = Student("张三", 18, 90)
stu.show_info()

输出:

张三,18岁,成绩:90

这里:

super().__init__(name, age)

表示调用父类 Person 的初始化方法。

通俗理解:

父类已经写好的初始化工作,子类不用重复写。
用 super() 请父类先完成它那部分工作。
然后子类再补充自己的属性。

10. 方法重写

子类可以重新定义父类中已经存在的方法。

这叫方法重写,也叫方法覆盖。

示例:

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


class Dog(Animal):
    def speak(self):
        print("狗会汪汪叫")


dog = Dog()
dog.speak()

输出:

狗会汪汪叫

虽然父类 Animal 中有 speak() 方法,但是子类 Dog 中也定义了 speak()

当子类对象调用 speak() 时,会优先使用子类自己的方法。

通俗理解:

父类有一个默认版本。
子类觉得不合适,就可以写一个自己的版本。

11. 重写后还能调用父类方法吗

可以。

使用 super() 可以在子类方法中调用父类方法。

示例:

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


class Dog(Animal):
    def speak(self):
        super().speak()
        print("狗会汪汪叫")


dog = Dog()
dog.speak()

输出:

动物会发出声音
狗会汪汪叫

这里:

super().speak()

表示先调用父类的 speak(),然后再执行子类自己的代码。

这种写法适合:

父类已有逻辑还要保留。
子类只是在父类基础上进行补充。

12. 继承中的方法查找顺序

当子类对象调用一个方法时,Python 会按顺序查找:

1. 先在子类中找。
2. 如果子类中没有,就去父类中找。
3. 如果父类中还没有,就继续往更上层父类找。
4. 如果都找不到,就报错。

示例:

class Animal:
    def eat(self):
        print("动物吃东西")


class Dog(Animal):
    def bark(self):
        print("狗叫")


dog = Dog()

dog.bark()
dog.eat()

输出:

狗叫
动物吃东西

调用 dog.bark()

Dog 类中有 bark(),直接使用。

调用 dog.eat()

Dog 类中没有 eat()。
去父类 Animal 中找。
Animal 中有 eat(),所以使用父类方法。

13. 单继承

单继承表示一个子类只继承一个父类。

语法:

class 子类(父类):
    pass

示例:

class Person:
    def say_hello(self):
        print("你好")


class Student(Person):
    def study(self):
        print("正在学习")


stu = Student()
stu.say_hello()
stu.study()

输出:

你好
正在学习

初学阶段,重点掌握单继承即可。

单继承结构比较清楚,适合教学和入门。

14. 多层继承

多层继承表示一个类继承另一个类,而另一个类又继承更上层的类。

例如:

Animal -> Dog -> PoliceDog

代码示例:

class Animal:
    def eat(self):
        print("动物吃东西")


class Dog(Animal):
    def bark(self):
        print("狗叫")


class PoliceDog(Dog):
    def work(self):
        print("警犬正在工作")


dog = PoliceDog()
dog.eat()
dog.bark()
dog.work()

输出:

动物吃东西
狗叫
警犬正在工作

这里:

PoliceDog 继承 Dog。
Dog 继承 Animal。
所以 PoliceDog 可以使用 Dog 和 Animal 中的方法。

通俗理解:

子类可以继承父类。
也可以间接继承爷爷类中的内容。

15. 多继承

多继承表示一个子类同时继承多个父类。

语法:

class 子类(父类1, 父类2):
    pass

示例:

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


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


class Duck(Flyable, Swimmable):
    pass


duck = Duck()
duck.fly()
duck.swim()

输出:

可以飞
可以游泳

这里:

Duck 同时继承了 Flyable 和 Swimmable。
所以 Duck 对象既可以 fly(),也可以 swim()。

注意:

多继承功能强大,但也更容易复杂。
初学阶段先重点掌握单继承。

16. 多继承中的同名方法

如果多个父类中有同名方法,子类调用时会使用哪一个?

看示例:

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

因为 C(A, B) 中,A 写在 B 前面。

Python 会按照方法解析顺序查找方法。

可以用 __mro__ 查看查找顺序。

print(C.__mro__)

输出类似:

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

这表示查找顺序是:

C -> A -> B -> object

所以会先找到 A 中的 hello()

17. MRO 是什么

MRO 是 Method Resolution Order 的缩写。

中文可以理解为:

方法解析顺序。

当一个对象调用方法时,Python 会按照 MRO 顺序查找方法。

示例:

class A:
    pass


class B(A):
    pass


class C(B):
    pass


print(C.__mro__)

输出类似:

(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

这说明:

C 的方法查找顺序是 C -> B -> A -> object。

教学中可以简单讲:

MRO 告诉我们,子类对象调用方法时,Python 到底按什么顺序找方法。

18. object 是所有类的根类

在 Python 3 中,所有类最终都继承自 object

下面两种写法效果基本一样:

class Person:
    pass
class Person(object):
    pass

可以查看:

class Person:
    pass


print(Person.__mro__)

输出类似:

(<class '__main__.Person'>, <class 'object'>)

这说明:

Person 最终继承自 object。

初学阶段一般写:

class Person:
    pass

即可。

19. issubclass() 判断继承关系

issubclass() 可以判断一个类是否是另一个类的子类。

语法:

issubclass(子类, 父类)

示例:

class Animal:
    pass


class Dog(Animal):
    pass


print(issubclass(Dog, Animal))
print(issubclass(Animal, Dog))

输出:

True
False

解释:

Dog 是 Animal 的子类,所以第一个结果是 True。
Animal 不是 Dog 的子类,所以第二个结果是 False。

20. isinstance() 判断对象类型

isinstance() 可以判断一个对象是否属于某个类。

示例:

class Animal:
    pass


class Dog(Animal):
    pass


dog = Dog()

print(isinstance(dog, Dog))
print(isinstance(dog, Animal))

输出:

True
True

为什么 dog 也是 Animal 类型?

因为:

Dog 继承 Animal。
dog 是 Dog 对象。
所以 dog 也可以看作一种 Animal。

再看:

animal = Animal()

print(isinstance(animal, Animal))
print(isinstance(animal, Dog))

输出:

True
False

动物对象不一定是狗对象。

教学记忆:

子类对象也是父类对象的一种。
父类对象不一定是子类对象。

21. 类属性在继承中的表现

子类也可以访问父类的类属性。

class Person:
    species = "人类"


class Student(Person):
    pass


print(Student.species)

stu = Student()
print(stu.species)

输出:

人类
人类

如果子类定义了同名类属性,会优先使用子类自己的。

class Person:
    role = "普通人"


class Student(Person):
    role = "学生"


stu = Student()

print(Person.role)
print(Student.role)
print(stu.role)

输出:

普通人
学生
学生

这说明:

子类可以继承父类类属性。
子类也可以定义同名类属性来覆盖父类中的值。

22. 实例属性在继承中的表现

实例属性通常由 __init__() 创建。

如果子类调用了父类的 __init__(),就可以拥有父类初始化的实例属性。

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


class Student(Person):
    def __init__(self, name, score):
        super().__init__(name)
        self.score = score


stu = Student("张三", 90)

print(stu.name)
print(stu.score)

输出:

张三
90

这里:

name 来自父类初始化方法。
score 来自子类初始化方法。

23. 继承关系应该符合 is-a 关系

使用继承时,要判断子类是不是父类的一种。

这叫 is-a 关系。

例如:

狗是动物。
猫是动物。
学生是人。
教师是人。

这些适合使用继承。

代码:

class Animal:
    pass


class Dog(Animal):
    pass

可以读成:

Dog is an Animal.
狗是一种动物。

不合适的例子:

汽车有轮子。

不能说:

汽车是轮子。

所以不应该写:

class Car(Wheel):
    pass

更合适的理解是:

汽车拥有轮子。

这属于 has-a 关系,不适合用继承表达。

教学总结:

能说“子类是一种父类”,才适合使用继承。

24. 继承不要滥用

继承可以减少重复代码,但不能为了少写代码就随便继承。

不合适:

学生类继承课程类。
订单类继承用户类。
汽车类继承轮子类。

因为这些关系都不能自然读成:

学生是一种课程。
订单是一种用户。
汽车是一种轮子。

继承应该表达清晰的分类关系。

推荐:

Student 继承 Person。
Dog 继承 Animal。
Circle 继承 Shape。

因为这些可以读成:

学生是一种人。
狗是一种动物。
圆形是一种图形。

25. 继承和重复代码

继承常用于提取公共代码。

没有继承:

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


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

这里 StudentTeacher 都有 nameage

可以提取到父类 Person 中:

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


class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name, age)
        self.score = score


class Teacher(Person):
    def __init__(self, name, age, subject):
        super().__init__(name, age)
        self.subject = subject

这样:

Person 管理人的共同信息。
Student 管理学生特有信息。
Teacher 管理教师特有信息。

26. 综合案例:学生和教师

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

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


class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name, age)
        self.score = score

    def study(self):
        print(f"{self.name}正在学习")

    def show_score(self):
        print(f"{self.name}的成绩是{self.score}")


class Teacher(Person):
    def __init__(self, name, age, subject):
        super().__init__(name, age)
        self.subject = subject

    def teach(self):
        print(f"{self.name}正在教{self.subject}")


stu = Student("张三", 18, 90)
teacher = Teacher("王老师", 35, "Python")

stu.introduce()
stu.study()
stu.show_score()

teacher.introduce()
teacher.teach()

输出:

我叫张三,今年18岁
张三正在学习
张三的成绩是90
我叫王老师,今年35岁
王老师正在教Python

这个案例中:

Person 是父类。
Student 和 Teacher 是子类。
name、age 是公共属性。
introduce() 是公共方法。
score 是学生特有属性。
subject 是教师特有属性。
study() 是学生特有方法。
teach() 是教师特有方法。

27. 综合案例:图形类

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

    def show_name(self):
        print(f"图形名称:{self.name}")


class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("矩形")
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height


class Circle(Shape):
    def __init__(self, radius):
        super().__init__("圆形")
        self.radius = radius

    def area(self):
        return 3.14 * self.radius * self.radius


rect = Rectangle(3, 4)
circle = Circle(5)

rect.show_name()
print(rect.area())

circle.show_name()
print(circle.area())

输出:

图形名称:矩形
12
图形名称:圆形
78.5

这个案例适合讲:

不同子类可以继承同一个父类。
子类可以有自己的属性和方法。
子类也可以定义和父类同名的方法。

28. 综合案例:员工类

class Employee:
    def __init__(self, name, base_salary):
        self.name = name
        self.base_salary = base_salary

    def show_info(self):
        print(f"员工:{self.name},基本工资:{self.base_salary}")


class Manager(Employee):
    def __init__(self, name, base_salary, bonus):
        super().__init__(name, base_salary)
        self.bonus = bonus

    def total_salary(self):
        return self.base_salary + self.bonus


manager = Manager("李经理", 8000, 3000)

manager.show_info()
print(manager.total_salary())

输出:

员工:李经理,基本工资:8000
11000

这个案例中:

Manager 是 Employee 的子类。
Manager 继承了 Employee 的 name、base_salary 和 show_info()。
Manager 新增了 bonus 和 total_salary()。

29. 常见错误 1:子类写了 init 却忘记调用父类 init

错误示例:

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


class Student(Person):
    def __init__(self, name, score):
        self.score = score

    def show_info(self):
        print(self.name, self.score)


stu = Student("张三", 90)
stu.show_info()

会报错。

原因:

Student 自己写了 __init__()。
但是没有调用 Person 的 __init__()。
所以对象没有 name 属性。

正确写法:

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


class Student(Person):
    def __init__(self, name, score):
        super().__init__(name)
        self.score = score

    def show_info(self):
        print(self.name, self.score)

30. 常见错误 2:super() 参数传错

错误示例:

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


class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name)
        self.score = score

会报错,因为父类 Person.__init__() 需要 nameage 两个参数。

正确写法:

class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name, age)
        self.score = score

注意:

调用父类方法时,传入的参数要和父类方法要求的一致。

31. 常见错误 3:继承关系设计不合理

不合理:

class Wheel:
    pass


class Car(Wheel):
    pass

原因:

汽车不是一种轮子。
汽车只是拥有轮子。

更适合继承的关系:

class Vehicle:
    pass


class Car(Vehicle):
    pass

因为:

汽车是一种交通工具。

判断方法:

能不能自然说出“子类是一种父类”。

32. 常见错误 4:把父类和子类写反

错误理解:

动物继承狗。

这是反的。

正确理解:

狗继承动物。

代码:

class Animal:
    pass


class Dog(Animal):
    pass

因为:

狗是一种动物。
动物不一定是狗。

33. 常见错误 5:方法重写后以为父类方法还会自动执行

示例:

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


class Dog(Animal):
    def speak(self):
        print("狗会汪汪叫")


dog = Dog()
dog.speak()

输出:

狗会汪汪叫

父类的 speak() 不会自动执行。

如果想执行父类方法,需要手动调用:

class Dog(Animal):
    def speak(self):
        super().speak()
        print("狗会汪汪叫")

34. 常见错误 6:多继承中同名方法结果不清楚

示例:

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


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


class C(A, B):
    pass

C 对象调用 hello() 时,会使用 A 中的方法。

c = C()
c.hello()

输出:

A

原因是:

class C(A, B):

A 写在前面。

如果不确定,可以查看:

print(C.__mro__)

教学建议:

初学阶段不要设计太复杂的多继承。
如果多个父类有同名方法,要特别小心。

35. 常见错误 7:以为继承会复制代码

继承不是把父类代码复制一份到子类里。

更准确地说:

子类对象调用方法时,如果子类中找不到,就去父类中查找。

所以继承是一种代码复用机制,不是简单复制粘贴。

36. 注意事项 1:优先保证继承关系清晰

继承最好表达清楚的分类关系。

推荐:

Student 继承 Person。
Teacher 继承 Person。
Dog 继承 Animal。
Circle 继承 Shape。

不推荐:

Order 继承 User。
Car 继承 Wheel。
Student 继承 Course。

判断标准:

子类是不是父类的一种?

37. 注意事项 2:子类重写 init 时常常需要 super()

如果子类只新增少量属性,通常应该这样写:

class Parent:
    def __init__(self, a):
        self.a = a


class Child(Parent):
    def __init__(self, a, b):
        super().__init__(a)
        self.b = b

这样可以保留父类初始化逻辑。

教学记忆:

子类写 init,先想 super。

38. 注意事项 3:不要为了复用一个方法就强行继承

有时候只是想使用某个功能,不一定要用继承。

例如:

类 A 里有一个格式化字符串的方法。
类 B 想使用这个方法。

这不一定说明 B 应该继承 A

继承表达的是“是什么”的关系,不是“想用某个函数”的关系。

简单判断:

如果只是想复用工具函数,可以考虑普通函数。
如果确实是父子分类关系,再考虑继承。

39. 注意事项 4:父类应该放公共内容

父类中应该放子类共有的属性和方法。

例如:

Person:
    name
    age
    introduce()

Student:
    score
    study()

Teacher:
    subject
    teach()

不要把只有某个子类才需要的方法放到父类中。

例如:

只有 Student 需要 study()。
就不要把 study() 放到 Person 中。

40. 注意事项 5:重写方法时保持方法含义一致

如果子类重写父类方法,最好保持方法含义一致。

例如:

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


class Dog(Animal):
    def speak(self):
        print("狗叫")

这是合理的,因为都是“发声”。

不推荐:

class Dog(Animal):
    def speak(self):
        print("开始计算工资")

这样虽然语法上可以,但含义混乱。

41. 注意事项 6:继承层级不要太深

多层继承可以使用,但层级太深会让代码难以理解。

例如:

A -> B -> C -> D -> E -> F

F 调用一个方法时,很难马上知道这个方法来自哪里。

教学建议:

初学阶段继承层级控制在 1 到 2 层。

代码越清楚,越适合教学和维护。

42. 注意事项 7:多继承要谨慎

多继承可以让一个类同时获得多个父类的功能。

但如果多个父类有同名方法,查找顺序会变复杂。

初学阶段建议:

先掌握单继承。
多继承了解即可。

如果使用多继承,要学会查看:

类名.__mro__

43. 注意事项 8:父类修改可能影响所有子类

如果多个子类都继承同一个父类,那么修改父类方法可能影响所有子类。

示例:

class Animal:
    def eat(self):
        print("动物吃东西")


class Dog(Animal):
    pass


class Cat(Animal):
    pass

如果修改了 Animal.eat(),那么 DogCateat() 都会受到影响。

这既是继承的优点,也是需要注意的地方。

优点:公共逻辑只需要改一处。
注意:修改父类时要考虑所有子类。

44. 课堂练习 1:基础继承

要求:

  1. 定义 Animal 类。
  2. Animal 中定义 eat() 方法。
  3. 定义 Dog 类继承 Animal
  4. 创建 Dog 对象并调用 eat()

参考答案:

class Animal:
    def eat(self):
        print("正在吃东西")


class Dog(Animal):
    pass


dog = Dog()
dog.eat()

45. 课堂练习 2:子类添加方法

要求:

  1. 定义 Animal 类,有 eat() 方法。
  2. 定义 Dog 类继承 Animal
  3. Dog 类新增 bark() 方法。

参考答案:

class Animal:
    def eat(self):
        print("正在吃东西")


class Dog(Animal):
    def bark(self):
        print("汪汪叫")


dog = Dog()
dog.eat()
dog.bark()

46. 课堂练习 3:继承父类属性

要求:

  1. 定义 Person 类,有 name 属性。
  2. 定义 Student 类继承 Person
  3. 创建学生对象并打印姓名。

参考答案:

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


class Student(Person):
    pass


stu = Student("张三")
print(stu.name)

47. 课堂练习 4:子类新增属性

要求:

  1. 定义 Person 类,有 nameage 属性。
  2. 定义 Student 类继承 Person
  3. Student 新增 score 属性。
  4. 使用 super() 调用父类初始化方法。

参考答案:

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


class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name, age)
        self.score = score


stu = Student("张三", 18, 90)
print(stu.name)
print(stu.age)
print(stu.score)

48. 课堂练习 5:方法重写

要求:

  1. 定义 Animal 类,有 speak() 方法。
  2. 定义 Dog 类继承 Animal
  3. Dog 中重写 speak() 方法。

参考答案:

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


class Dog(Animal):
    def speak(self):
        print("狗会汪汪叫")


dog = Dog()
dog.speak()

49. 课堂练习 6:重写时调用父类方法

要求:

  1. 定义 Animal 类,有 speak() 方法。
  2. 定义 Dog 类继承 Animal
  3. Dog.speak() 中先调用父类 speak(),再输出狗自己的声音。

参考答案:

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


class Dog(Animal):
    def speak(self):
        super().speak()
        print("狗会汪汪叫")


dog = Dog()
dog.speak()

50. 课堂练习 7:判断继承关系

阅读代码,判断输出:

class Animal:
    pass


class Dog(Animal):
    pass


dog = Dog()

print(isinstance(dog, Dog))
print(isinstance(dog, Animal))
print(issubclass(Dog, Animal))

答案:

True
True
True

解释:

dog 是 Dog 对象。
Dog 继承 Animal。
所以 dog 也可以看作 Animal 对象。

51. 课堂练习 8:多层继承

要求:

  1. 定义 Animal 类,有 eat() 方法。
  2. 定义 Dog 类继承 Animal,有 bark() 方法。
  3. 定义 PoliceDog 类继承 Dog,有 work() 方法。
  4. 创建 PoliceDog 对象,调用三个方法。

参考答案:

class Animal:
    def eat(self):
        print("动物吃东西")


class Dog(Animal):
    def bark(self):
        print("狗叫")


class PoliceDog(Dog):
    def work(self):
        print("警犬工作")


dog = PoliceDog()
dog.eat()
dog.bark()
dog.work()

52. 课堂练习 9:找错误

下面代码有什么问题?

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


class Student(Person):
    def __init__(self, name, score):
        self.score = score


stu = Student("张三", 90)
print(stu.name)

答案:

Student 重写了 __init__(),但是没有调用父类的 __init__()。
所以 stu 没有 name 属性。

正确写法:

class Student(Person):
    def __init__(self, name, score):
        super().__init__(name)
        self.score = score

53. 课堂练习 10:判断是否适合继承

下面哪些关系适合使用继承?

1. 狗 和 动物
2. 学生 和 人
3. 汽车 和 轮子
4. 老师 和 人
5. 订单 和 用户

参考答案:

适合继承:
1. 狗 和 动物
2. 学生 和 人
4. 老师 和 人

不适合继承:
3. 汽车 和 轮子
5. 订单 和 用户

原因:

狗是一种动物。
学生是一种人。
老师是一种人。

汽车不是一种轮子,汽车是拥有轮子。
订单不是一种用户,订单属于用户或由用户创建。

54. 教学总结

继承是 Python 面向对象编程中用来复用代码和表达类之间关系的重要机制。

一句话总结:

继承就是子类可以使用父类中已有的属性和方法。

核心概念:

  1. 被继承的类叫父类,也叫基类。
  2. 继承别人的类叫子类,也叫派生类。
  3. 子类可以使用父类的方法。
  4. 子类可以使用父类初始化出来的属性。
  5. 子类可以添加自己的属性和方法。
  6. 子类可以重写父类方法。
  7. super() 常用于调用父类方法。
  8. 子类重写 __init__() 时,常常需要调用 super().__init__()
  9. 继承关系应该符合“子类是一种父类”的关系。
  10. 初学阶段重点掌握单继承。

最常用代码模板:

class 父类:
    def __init__(self, 公共属性):
        self.公共属性 = 公共属性

    def 公共方法(self):
        pass


class 子类(父类):
    def __init__(self, 公共属性, 子类特有属性):
        super().__init__(公共属性)
        self.子类特有属性 = 子类特有属性

    def 子类特有方法(self):
        pass

学生和人的示例:

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

    def introduce(self):
        print(f"我叫{self.name}")


class Student(Person):
    def __init__(self, name, score):
        super().__init__(name)
        self.score = score

    def show_score(self):
        print(f"{self.name}的成绩是{self.score}")


stu = Student("张三", 90)
stu.introduce()
stu.show_score()

课堂记忆口诀:

父类放公共,
子类写特殊。
子类继承父类,
先找自己,再找父亲。
重写用同名,
扩展用 super。
能说“是一种”,再考虑继承。

最后记住:

继承不是为了炫技,而是为了减少重复代码,并让类之间的关系更清楚。
0

评论区