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}正在抓老鼠")
这段代码中,Dog 和 Cat 都有:
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
这里 Student 和 Teacher 都有 name 和 age。
可以提取到父类 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__() 需要 name 和 age 两个参数。
正确写法:
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(),那么 Dog 和 Cat 的 eat() 都会受到影响。
这既是继承的优点,也是需要注意的地方。
优点:公共逻辑只需要改一处。
注意:修改父类时要考虑所有子类。
44. 课堂练习 1:基础继承
要求:
- 定义
Animal类。 - 在
Animal中定义eat()方法。 - 定义
Dog类继承Animal。 - 创建
Dog对象并调用eat()。
参考答案:
class Animal:
def eat(self):
print("正在吃东西")
class Dog(Animal):
pass
dog = Dog()
dog.eat()
45. 课堂练习 2:子类添加方法
要求:
- 定义
Animal类,有eat()方法。 - 定义
Dog类继承Animal。 Dog类新增bark()方法。
参考答案:
class Animal:
def eat(self):
print("正在吃东西")
class Dog(Animal):
def bark(self):
print("汪汪叫")
dog = Dog()
dog.eat()
dog.bark()
46. 课堂练习 3:继承父类属性
要求:
- 定义
Person类,有name属性。 - 定义
Student类继承Person。 - 创建学生对象并打印姓名。
参考答案:
class Person:
def __init__(self, name):
self.name = name
class Student(Person):
pass
stu = Student("张三")
print(stu.name)
47. 课堂练习 4:子类新增属性
要求:
- 定义
Person类,有name和age属性。 - 定义
Student类继承Person。 Student新增score属性。- 使用
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:方法重写
要求:
- 定义
Animal类,有speak()方法。 - 定义
Dog类继承Animal。 - 在
Dog中重写speak()方法。
参考答案:
class Animal:
def speak(self):
print("动物会发出声音")
class Dog(Animal):
def speak(self):
print("狗会汪汪叫")
dog = Dog()
dog.speak()
49. 课堂练习 6:重写时调用父类方法
要求:
- 定义
Animal类,有speak()方法。 - 定义
Dog类继承Animal。 - 在
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:多层继承
要求:
- 定义
Animal类,有eat()方法。 - 定义
Dog类继承Animal,有bark()方法。 - 定义
PoliceDog类继承Dog,有work()方法。 - 创建
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 面向对象编程中用来复用代码和表达类之间关系的重要机制。
一句话总结:
继承就是子类可以使用父类中已有的属性和方法。
核心概念:
- 被继承的类叫父类,也叫基类。
- 继承别人的类叫子类,也叫派生类。
- 子类可以使用父类的方法。
- 子类可以使用父类初始化出来的属性。
- 子类可以添加自己的属性和方法。
- 子类可以重写父类方法。
super()常用于调用父类方法。- 子类重写
__init__()时,常常需要调用super().__init__()。 - 继承关系应该符合“子类是一种父类”的关系。
- 初学阶段重点掌握单继承。
最常用代码模板:
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。
能说“是一种”,再考虑继承。
最后记住:
继承不是为了炫技,而是为了减少重复代码,并让类之间的关系更清楚。
评论区