无需打开直接搜索微信:本司针对手游进行,选择我们的四大理由: ...
2025-08-24 0
在 OOP 的三大特性中,继承是实现 “代码复用” 和 “功能扩展” 的核心机制。它模拟了现实世界中 “一般与特殊” 的关系 —— 例如 “人” 是一般概念,“学生”“教师” 是特殊概念,“学生” 和 “教师” 除了拥有 “人” 的共同特征(如姓名、年龄),还拥有各自的特殊特征(如学生的 “学号”、教师的 “工号”)。本章将从继承的基本概念、单继承的实现、方法重写、多继承的规则四个维度,全面讲解 Python 中继承的设计思路与代码实践。
继承(Inheritance)是指子类(Subclass)从父类(Parent Class,也称基类、超类)中继承属性和方法,同时子类可以添加自己独有的属性和方法,或修改父类已有的方法。这种机制让子类在复用父类代码的基础上,快速实现功能扩展,避免了重复编写相似逻辑。
我们以 “人” 和 “学生” 的关系为例,理解继承的核心思想:
若不使用继承,定义 “Person” 类和 “Student” 类时,需要重复编写 “姓名、年龄” 属性和 “吃饭、睡觉” 方法,导致代码冗余:
# 定义“人”类
class Person:
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 Student:
def __init__(self, name, age, student_id):
self.name = name # 重复定义:与Person类的name属性一致
self.age = age # 重复定义:与Person类的age属性一致
self.student_id = student_id # 学生独有的属性
# 重复定义:与Person类的eat方法一致
def eat(self):
print(f"{self.name}在吃饭")
# 重复定义:与Person类的sleep方法一致
def sleep(self):
print(f"{self.name}在睡觉")
# 学生独有的方法
def study(self):
print(f"学生{self.name}(学号:{self.student_id})在学习")
# 创建学生对象
student1 = Student("小明", 20, "2023001")
student1.eat() # 输出:小明在吃饭(重复代码)
student1.study() # 输出:学生小明(学号:2023001)在学习
问题分析:Student类中的name、age属性和eat、sleep方法与Person类完全一致,代码重复率高 —— 若后续需要修改 “吃饭” 的逻辑(如添加 “使用筷子” 的描述),需同时修改Person和Student两个类的eat方法,维护成本高。
通过继承,Student类(子类)可直接复用Person类(父类)的属性和方法,只需专注于新增自己的特殊功能:
# 定义父类:Person
class Person:
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}在睡觉")
# 定义子类:Student,继承自Person
class Student(Person):
# 子类的初始化方法:新增学生独有的属性student_id
def __init__(self, name, age, student_id):
# 调用父类的初始化方法,复用name和age的初始化逻辑
super().__init__(name, age)
# 新增学生独有的属性
self.student_id = student_id
# 新增学生独有的方法
def study(self):
print(f"学生{self.name}(学号:{self.student_id})在学习")
# 创建学生对象
student1 = Student("小明", 20, "2023001")
# 1. 调用从父类继承的方法
student1.eat() # 输出:小明在吃饭(复用父类方法)
student1.sleep() # 输出:小明在睡觉(复用父类方法)
# 2. 调用子类新增的方法
student1.study() # 输出:学生小明(学号:2023001)在学习
# 3. 访问从父类继承的属性和子类新增的属性
print(f"姓名:{student1.name},年龄:{student1.age},学号:{student1.student_id}")
# 输出:姓名:小明,年龄:20,学号:2023001
运行结果:
小明在吃饭
小明在睡觉
学生小明(学号:2023001)在学习
姓名:小明,年龄:20,学号:2023001
继承的优势体现:
在 Python 继承中,需理解以下关键术语:
Python 支持单继承(子类只继承一个父类)和多继承(子类继承多个父类),其中单继承是最常用的场景,语法简洁且逻辑清晰。
单继承的语法格式如下:
class 子类名(父类名):
"""子类的文档字符串"""
# 子类的初始化方法(可选,若需新增属性则定义)
def __init__(self, 父类参数, 子类新增参数):
# 调用父类的初始化方法,初始化父类属性
super().__init__(父类参数)
# 初始化子类新增的属性
self.子类新增属性 = 子类新增参数
# 子类新增的方法(可选)
def 子类方法名(self, 参数...):
pass
# 子类重写的父类方法(可选,后续5.3节讲解)
def 父类方法名(self, 参数...):
pass
继承支持 “多层继承”—— 子类可以再被其他类继承,形成继承链。例如:Person是父类,Student继承Person,CollegeStudent(大学生)继承Student,CollegeStudent会同时拥有Person和Student的所有属性和方法。
# 第一层父类:Person(人)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"大家好,我是{self.name},今年{self.age}岁")
# 第二层子类:Student(学生),继承Person
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age) # 调用Person的__init__
self.student_id = student_id # 新增学号属性
# 新增学习方法
def study(self):
print(f"学生{self.name}(学号:{self.student_id})在学习")
# 第三层子类:CollegeStudent(大学生),继承Student
class CollegeStudent(Student):
def __init__(self, name, age, student_id, major):
super().__init__(name, age, student_id) # 调用Student的__init__
self.major = major # 新增专业属性
# 新增参加社团方法
def join_club(self, club_name):
print(f"大学生{self.name}(专业:{self.major})加入了{club_name}社团")
# 创建大学生对象
cs1 = CollegeStudent("小明", 20, "2023001", "计算机科学")
# 1. 调用Person类的方法(多层继承)
cs1.introduce() # 输出:大家好,我是小明,今年20岁
# 2. 调用Student类的方法(多层继承)
cs1.study() # 输出:学生小明(学号:2023001)在学习
# 3. 调用CollegeStudent类的新增方法
cs1.join_club("编程社") # 输出:大学生小明(专业:计算机科学)加入了编程社
# 4. 访问所有层级的属性
print(f"姓名:{cs1.name}(Person),年龄:{cs1.age}(Person),")
print(f"学号:{cs1.student_id}(Student),专业:{cs1.major}(CollegeStudent)")
运行结果:
大家好,我是小明,今年20岁
学生小明(学号:2023001)在学习
大学生小明(专业:计算机科学)加入了编程社
姓名:小明(Person),年龄:20(Person),
学号:2023001(Student),专业:计算机科学(CollegeStudent)
多层继承的规则:子类会继承 “继承链上所有父类” 的属性和方法,调用父类方法时,super()会沿着继承链向上查找最近的父类方法(如CollegeStudent的super().__init__会先调用Student的__init__,Student的super().__init__再调用Person的__init__)。
super()函数是 Python 继承中非常重要的工具,它的主要作用是在子类中调用父类的方法,避免硬编码父类名(如直接写Person.__init__(self, name, age)),提高代码的灵活性和可维护性。
在子类的__init__方法中,super().__init__(参数)会调用父类的__init__方法,初始化父类的属性。这是super()最常用的场景。
示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
def __init__(self, name, age, student_id):
# 方式1:使用super()调用父类__init__(推荐)
super().__init__(name, age)
# 方式2:硬编码父类名调用(不推荐,若父类名修改需同步修改此处)
# Person.__init__(self, name, age)
self.student_id = student_id
student1 = Student("小明", 20, "2023001")
print(f"姓名:{student1.name},年龄:{student1.age},学号:{student1.student_id}")
# 输出:姓名:小明,年龄:20,学号:2023001
为什么推荐 super () 而非硬编码父类名?
若后续将Student的父类从Person改为Employee(如需求变更),使用super()的代码无需修改,而硬编码Person.__init__的代码需要同步修改为Employee.__init__,维护成本更高。
除了__init__方法,super()还可以调用父类的其他实例方法,适用于 “子类方法需要复用父类方法逻辑,并在此基础上扩展” 的场景。
示例:子类Student的introduce方法复用父类Person的introduce逻辑,并新增学号信息:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
# 父类的自我介绍逻辑
return f"大家好,我是{self.name},今年{self.age}岁"
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age)
self.student_id = student_id
def introduce(self):
# 1. 调用父类的introduce方法,复用基础逻辑
parent_intro = super().introduce()
# 2. 新增子类的特殊逻辑(添加学号信息)
student_intro = f"{parent_intro},我的学号是{self.student_id}"
print(student_intro)
# 创建学生对象并调用方法
student1 = Student("小明", 20, "2023001")
student1.introduce() # 输出:大家好,我是小明,今年20岁,我的学号是2023001
运行结果:
大家好,我是小明,今年20岁,我的学号是2023001
逻辑分析:子类Student的introduce方法没有完全重写父类逻辑,而是通过super().introduce()获取父类的自我介绍字符串,再拼接学号信息,实现 “复用 + 扩展” 的效果 —— 这比完全重写父类方法更高效,也更符合继承的设计思想。
在多层继承中,super()会沿着 “方法解析顺序(MRO)” 向上查找父类方法(MRO 后续 5.4.2 节详细讲解),确保每个父类的方法只被调用一次。
示例:
class A:
def show(self):
print("A类的show方法")
class B(A):
def show(self):
print("B类的show方法(开始)")
super().show() # 调用父类A的show方法
print("B类的show方法(结束)")
class C(B):
def show(self):
print("C类的show方法(开始)")
super().show() # 调用父类B的show方法
print("C类的show方法(结束)")
# 创建C类对象并调用show方法
c1 =</doubaocanvas>
C()
c1.show()
**运行结果**:
C 类的 show 方法(开始)
B 类的 show 方法(开始)
A 类的 show 方法
B 类的 show 方法(结束)
C 类的 show 方法(结束)
**逻辑分析**:调用`c1.show()`时,执行流程如下:
1. 先执行`C`类的`show`方法,打印“C类的show方法(开始)”;
2. 调用`super().show()`,沿着MRO找到`B`类的`show`方法,执行该方法,打印“B类的show方法(开始)”;
3. 在`B`类的`show`方法中调用`super().show()`,沿着MRO找到`A`类的`show`方法,执行该方法,打印“A类的show方法”;
4. `A`类的`show`方法执行完毕,回到`B`类,打印“B类的show方法(结束)”;
5. `B`类的`show`方法执行完毕,回到`C`类,打印“C类的show方法(结束)”。
可见,`super()`会严格按照MRO顺序查找父类方法,确保多层继承中的方法调用逻辑清晰且无重复。
## 5.3 方法重写(Override)
在继承关系中,子类可能需要修改父类已有的方法逻辑(如父类`Person`的`work`方法默认“上班”,子类`Student`的`work`方法应改为“学习”),这种“子类定义与父类同名方法,覆盖父类方法逻辑”的操作称为**方法重写**。
### 5.3.1 方法重写的场景:子类需要个性化行为
当父类的方法逻辑无法满足子类的需求时,就需要进行方法重写。例如:
- 父类`Animal`的`make_sound`方法默认“发出声音”,子类`Dog`的`make_sound`需重写为“汪汪叫”,子类`Cat`的`make_sound`需重写为“喵喵叫”;
- 父类`Vehicle`的`run`方法默认“以普通速度行驶”,子类`SportsCar`的`run`需重写为“以高速行驶”。
#### 示例:方法重写的基础实现(Animal→Dog/Cat)
```python
# 父类:Animal(动物)
class Animal:
def __init__(self, name):
self.name = name
# 父类的通用方法:发出声音(逻辑较笼统)
def make_sound(self):
print(f"{self.name}发出了声音")
# 子类1:Dog(狗),重写make_sound方法
class Dog(Animal):
def make_sound(self):
# 重写为“汪汪叫”的逻辑
print(f"{self.name}汪汪叫:汪!汪!")
# 子类2:Cat(猫),重写make_sound方法
class Cat(Animal):
def make_sound(self):
# 重写为“喵喵叫”的逻辑
print(f"{self.name}喵喵叫:喵~ 喵~")
# 创建对象并调用方法
dog1 = Dog("小黑")
cat1 = Cat("小白")
dog1.make_sound() # 输出:小黑汪汪叫:汪!汪!(调用子类重写的方法)
cat1.make_sound() # 输出:小白喵喵叫:喵~ 喵~(调用子类重写的方法)
# 父类对象调用方法(仍使用父类逻辑)
animal1 = Animal("不知名动物")
animal1.make_sound() # 输出:不知名动物发出了声音
运行结果:
小黑汪汪叫:汪!汪!
小白喵喵叫:喵~ 喵~
不知名动物发出了声音
方法重写的核心规则:
方法重写并非一定要完全抛弃父类逻辑,很多场景下,子类需要 “复用父类方法的部分逻辑,再添加自己的特殊逻辑”,此时可通过super()调用父类方法,实现 “复用 + 扩展”。
# 父类:Person
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
# 父类的基础自我介绍逻辑
print(f"大家好,我是{self.name},今年{self.age}岁")
# 子类:Student,重写introduce方法
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age)
self.student_id = student_id
def introduce(self):
# 1. 复用父类的基础逻辑
super().introduce()
# 2. 新增子类的特殊逻辑(添加学号信息)
print(f"我的学号是{self.student_id},很高兴成为一名学生!")
# 子类:Teacher,重写introduce方法
class Teacher(Person):
def __init__(self, name, age, subject):
super().__init__(name, age)
self.subject = subject
def introduce(self):
# 1. 复用父类的基础逻辑
super().introduce()
# 2. 新增子类的特殊逻辑(添加教授科目信息)
print(f"我教授{self.subject},希望和大家共同进步!")
# 创建对象并调用方法
student1 = Student("小明", 20, "2023001")
teacher1 = Teacher("李老师", 35, "数学")
print("=== 学生自我介绍 ===")
student1.introduce()
print("\n=== 老师自我介绍 ===")
teacher1.introduce()
运行结果:
=== 学生自我介绍 ===
大家好,我是小明,今年20岁
我的学号是2023001,很高兴成为一名学生!
=== 老师自我介绍 ===
大家好,我是李老师,今年35岁
我教授数学,希望和大家共同进步!
优势分析:
class Animal:
def make_sound(self):
print("发出声音")
class Dog(Animal):
# 错误:方法名拼写错误(make_sound→make_sounds),未重写父类方法
def make_sounds(self):
print("汪汪叫")
dog1 = Dog()
dog1.make_sound() # 输出:发出声音(调用父类方法,未触发重写)
解决方法:重写前仔细核对父类方法名,确保完全一致;大型项目中可使用 IDE 的 “重写方法” 功能(如 PyCharm 中按Ctrl+O选择要重写的方法),避免拼写错误。
class Person:
# 父类方法:2个参数(self+message)
def speak(self, message):
print(f"说:{message}")
class Student(Person):
# 错误:子类方法参数个数与父类不一致(少了message参数)
def speak(self):
print("学生说:大家好")
student1 = Student()
# 调用时传入参数,与子类方法参数个数不匹配,报错
try:
student1.speak("我是小明")
except TypeError as e:
print("调用报错:", e) # 输出:调用报错:speak() takes 1 positional argument but 2 were given
解决方法:确保子类重写方法的参数列表与父类兼容(推荐完全一致),若子类需要额外参数,可通过 “默认参数” 实现,如def speak(self, message, extra=""):,既兼容父类调用,又支持子类扩展。
Python 不仅支持单继承,还支持多继承—— 子类可以同时继承多个父类,从而拥有所有父类的属性和方法。多继承能实现更灵活的功能组合,但也会带来 “方法名冲突” 等问题,因此需要通过 “方法解析顺序(MRO)” 来规范方法的调用逻辑。
多继承的语法格式如下:
class 子类名(父类1, 父类2, 父类3, ...):
"""子类的文档字符串"""
def __init__(self, 父类1参数, 父类2参数, ...):
# 调用父类的初始化方法(需显式调用,super()默认只调用第一个父类)
父类1.__init__(self, 父类1参数)
父类2.__init__(self, 父类2参数)
# ... 其他父类的初始化
# 子类的方法(可重写父类方法)
pass
假设我们有两个独立的父类:Person(包含姓名、年龄属性)和StudyAbility(包含学习相关方法),Student类需要同时拥有 “人的属性” 和 “学习能力”,此时可通过多继承实现:
# 父类1:Person(人,包含基础属性)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"姓名:{self.name},年龄:{self.age}岁")
# 父类2:StudyAbility(学习能力,包含学习方法)
class StudyAbility:
def study(self, subject):
print(f"正在学习{subject}")
def do_homework(self):
print("正在做家庭作业")
# 子类:Student,同时继承Person和StudyAbility
class Student(Person, StudyAbility):
def __init__(self, name, age, student_id):
# 调用父类1(Person)的初始化方法
Person.__init__(self, name, age)
# 调用父类2(StudyAbility)的初始化方法(若父类2无__init__,可省略)
# StudyAbility.__init__(self)
self.student_id = student_id # 子类新增属性
# 创建Student对象
student1 = Student("小明", 20, "2023001")
# 1. 调用父类1(Person)的方法
student1.introduce() # 输出:姓名:小明,年龄:20岁
# 2. 调用父类2(StudyAbility)的方法
student1.study("数学") # 输出:正在学习数学
student1.do_homework() # 输出:正在做家庭作业
# 3. 访问子类新增属性
print(f"学号:{student1.student_id}") # 输出:学号:2023001
运行结果:
姓名:小明,年龄:20岁
正在学习数学
正在做家庭作业
学号:2023001
多继承的优势:实现 “功能组合”—— 子类无需重复编写多个父类的功能,只需通过继承将多个独立的功能模块组合在一起(如Student=“人”+“学习能力”)。
当多继承的多个父类拥有同名方法时,子类调用该方法会优先执行哪个父类的逻辑?这就需要通过 “方法解析顺序(Method Resolution Order,简称 MRO)” 来确定 ——Python 会按照特定的顺序(C3 线性化算法)遍历父类,找到第一个匹配的方法并执行。
每个类都有__mro__属性和mro()方法,用于查看该类的方法解析顺序,返回结果为 “类的元组”,顺序从左到右,优先级依次降低。
class A:
def show(self):
print("A类的show方法")
class B(A):
def show(self):
print("B类的show方法")
class C(A):
def show(self):
print("C类的show方法")
# 子类D同时继承B和C,父类顺序为(B, C)
class D(B, C):
pass
# 查看D类的MRO
print("D类的MRO(__mro__属性):", D.__mro__)
print("D类的MRO(mro()方法):", D.mro())
# 创建D类对象并调用show方法(按MRO顺序执行第一个匹配的方法)
d1 = D()
d1.show() # 输出:B类的show方法(因为MRO中B在C前面)
运行结果:
D类的MRO(__mro__属性): (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D类的MRO(mro()方法): [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
B类的show方法
MRO 顺序分析:
Python 的 MRO 遵循以下核心规则,确保方法查找逻辑清晰且无矛盾:
当多继承的父类存在同名方法,且子类需要调用非 MRO 优先的父类方法时,可通过 “显式指定父类名” 的方式调用,或在子类中重写方法,自定义逻辑。
class B:
def show(self):
print("B类的show方法")
class C:
def show(self):
print("C类的show方法")
class D(B, C):
def call_parent_show(self):
# 显式调用B类的show方法
B.show(self)
# 显式调用C类的show方法
C.show(self)
d1 = D()
d1.call_parent_show()
运行结果:
B类的show方法
C类的show方法
class B:
def show(self):
return "B类的</doubaocanvas>
内容 ")
class C:
def show (self):
return "C 类的内容"
class D(B, C):
def show(self):
b_content = B.show (self) # 调用 B 类的 show 方法
c_content = C.show (self) # 调用 C 类的 show 方法
return f"D 类整合结果:{b_content} + {c_content}"
d1 = D ()
print (d1.show ()) # 输出:D 类整合结果:B 类的内容 + C 类的内容
**运行结果**:
D 类整合结果:B 类的内容 + C 类的内容
### 5.4.3 多继承的注意事项:避免“菱形继承”陷阱
多继承虽然灵活,但也存在风险,其中最典型的是“菱形继承”(也称“钻石继承”)——子类的两个父类同时继承自同一个祖父类,形成“菱形”的继承结构。这种结构可能导致祖父类的方法被重复调用(若未使用`super()`),或方法查找逻辑混乱。
#### 1. 菱形继承的结构示例
A(祖父类)
/
B C(父类)
\ /
D(子类)
#### 2. 未使用super()的问题:祖父类方法重复调用
若子类的父类在初始化时未使用`super()`,而是硬编码调用祖父类的方法,会导致祖父类的方法被重复调用,造成逻辑错误或资源浪费。
**错误案例**:
```python
class A:
def __init__(self):
print("A类的__init__方法被调用")
class B(A):
def __init__(self):
# 硬编码调用A的__init__(未使用super())
A.__init__(self)
print("B类的__init__方法被调用")
class C(A):
def __init__(self):
# 硬编码调用A的__init__(未使用super())
A.__init__(self)
print("C类的__init__方法被调用")
class D(B, C):
def __init__(self):
# 调用B和C的__init__
B.__init__(self)
C.__init__(self)
print("D类的__init__方法被调用")
# 创建D类对象(A的__init__被调用2次,重复初始化)
d1 = D()
运行结果:
A类的__init__方法被调用
B类的__init__方法被调用
A类的__init__方法被调用
C类的__init__方法被调用
D类的__init__方法被调用
问题分析:D类的__init__调用B和C的__init__,而B和C的__init__又分别调用A的__init__,导致A的__init__被重复调用 2 次 —— 若A的__init__中有资源初始化(如打开文件、创建数据库连接),会造成资源浪费或冲突。
在菱形继承中,所有父类的__init__方法都应使用super()调用,Python 会根据 MRO 顺序自动确保祖父类的方法只被调用一次。
正确案例:
class A:
def __init__(self):
super().__init__() # 使用super()调用下一个父类(按MRO)
print("A类的__init__方法被调用")
class B(A):
def __init__(self):
super().__init__() # 使用super()调用A的__init__
print("B类的__init__方法被调用")
class C(A):
def __init__(self):
super().__init__() # 使用super()调用A的__init__(但MRO确保只调用一次)
print("C类的__init__方法被调用")
class D(B, C):
def __init__(self):
super().__init__() # 使用super()调用B的__init__
print("D类的__init__方法被调用")
# 查看D类的MRO
print("D类的MRO:", D.__mro__)
# 创建D类对象(A的__init__只被调用1次)
d1 = D()
运行结果:
D类的MRO: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
A类的__init__方法被调用
C类的__init__方法被调用
B类的__init__方法被调用
D类的__init__方法被调用
逻辑分析:
示例:Mixin 类的使用(为 Student 添加日志功能)
# Mixin类:日志功能(仅用于被继承,不单独实例化)
class LogMixin:
def log(self, message):
# 模拟日志记录:打印时间和消息
import datetime
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{current_time}] 日志:{message}")
# 父类:Person
class Person:
def __init__(self, name):
self.name = name
# 子类:Student,继承Person(主父类)和LogMixin(功能Mixin类)
class Student(Person, LogMixin):
def study(self, subject):
# 调用Mixin类的log方法
self.log(f"{self.name}开始学习{subject}")
print(f"{self.name}正在学习{subject}")
# 创建Student对象
student1 = Student("小明")
student1.study("数学") # 同时拥有Person的属性和LogMixin的日志功能
运行结果:
[2025-08-24 15:30:00] 日志:小明开始学习数学
小明正在学习数学
本实战将综合继承、方法重写、super () 调用等核心知识点,设计一个 “人员管理” 的基础案例,具体需求如下:
class Person:
def __init__(self, name, age):
# 校验姓名:非空字符串
if not isinstance(name, str) or len(name.strip()) == 0:
raise ValueError("姓名必须是非空字符串")
# 校验年龄:0-150的整数
if not isinstance(age, int) or age < 0 or age > 150:
raise ValueError("年龄必须是0-150之间的整数")
self.name = name.strip()
self.age = age
def work(self):
# 父类通用工作方法
print(f"{self.name}正在工作")
def introduce(self):
# 自我介绍方法
print(f"大家好,我是{self.name},今年{self.age}岁")
class Student(Person):
def __init__(self, name, age, student_id, grade):
# 调用父类__init__,初始化姓名和年龄
super().__init__(name, age)
# 校验学号:非空字符串
if not isinstance(student_id, str) or len(student_id.strip()) == 0:
raise ValueError("学号必须是非空字符串")
# 校验年级:非空字符串
if not isinstance(grade, str) or len(grade.strip()) == 0:
raise ValueError("年级必须是非空字符串")
self.student_id = student_id.strip()
self.grade = grade.strip()
def work(self):
# 重写work方法:学生的“工作”是学习
print(f"{self.name}(学号:{self.student_id})正在学习,年级:{self.grade}")
def do_homework(self, subject):
# 新增方法:做家庭作业
if not isinstance(subject, str) or len(subject.strip()) == 0:
print("科目不能为空")
return
print(f"{self.name}正在做{subject.strip()}作业")
class Teacher(Person):
def __init__(self, name, age, teacher_id, subject):
# 调用父类__init__,初始化姓名和年龄
super().__init__(name, age)
# 校验教师编号:非空字符串
if not isinstance(teacher_id, str) or len(teacher_id.strip()) == 0:
raise ValueError("教师编号必须是非空字符串")
# 校验教授科目:非空字符串
if not isinstance(subject, str) or len(subject.strip()) == 0:
raise ValueError("教授科目必须是非空字符串")
self.teacher_id = teacher_id.strip()
self.subject = subject.strip()
def work(self):
# 重写work方法:教师的“工作”是教学
print(f"{self.name}(教师编号:{self.teacher_id})正在教授{self.subject}")
def correct_homework(self, student_name):
# 新增方法:批改作业
if not isinstance(student_name, str) or len(student_name.strip()) == 0:
print("学生姓名不能为空")
return
print(f"{self.name}正在批改{student_name.strip()}的作业")
# 1. 创建Student对象并调用方法
print("=== 学生操作 ===")
try:
student1 = Student("小明 ", 20, " 2023001 ", " 大二 ") # 带空格,strip()处理
student1.introduce() # 调用父类方法
student1.work() # 调用重写的方法
student1.do_homework("数学") # 调用新增方法
except ValueError as e:
print("创建学生对象失败:", e)
# 2. 创建Teacher对象并调用方法
print("\n=== 教师操作 ===")
try:
teacher1 = Teacher("李老师", 35, "T202301", "数学")
teacher1.introduce() # 调用父类方法
teacher1.work() # 调用重写的方法
teacher1.correct_homework("小明") # 调用新增方法
except ValueError as e:
print("创建教师对象失败:", e)
# 3. 创建Person对象并调用方法
print("\n=== 父类Person操作 ===")
try:
person1 = Person("王工", 40)
person1.introduce()
person1.work()
except ValueError as e:
print("创建Person对象失败:", e)
# 4. 测试参数校验(创建非法对象)
print("\n=== 非法对象测试 ===")
try:
Student("", 20, "2023002", "大二") # 姓名为空
except ValueError as e:
print("创建学生失败:", e)
try:
Teacher("张老师", 200, "T202302", "英语") # 年龄超出范围
except ValueError as e:
print("创建教师失败:", e)
=== 学生操作 ===
大家好,我是小明,今年20岁
小明(学号:2023001)正在学习,年级:大二
小明正在做数学作业
=== 教师操作 ===
大家好,我是李老师,今年35岁
李老师(教师编号:T202301)正在教授数学
李老师正在批改小明的作业
=== 父类Person操作 ===
大家好,我是王工,今年40岁
王工正在工作
=== 非法对象测试 ===
创建学生失败:姓名必须是非空字符串
创建教师失败:年龄必须是0-150之间的整数
通过本次实战,我们巩固了以下核心知识点:
相关文章
据环球网报道,国民党主席改选时程已经定下,9月4、5日登记,10月18日投票,11月1日交接。8月23日还有一场全台关注的第二轮罢免案,蓝营把“反恶罢...
2025-08-24 0
说起抗日战争那段历史,很多人都知道南京大屠杀或者731部队那些事,但在北京长辛店这个地方,日军干出的勾当也够让人脊背发凉的。那是1938年底的事,日军...
2025-08-24 0
谁能想到?外卖江湖沉寂多年后,真正打破平衡的,不是饿了么,不是抖音,而是淘宝闪购。8月以来,淘宝闪购的订单量连续突破 1 亿单,在关键节点甚至压过了美...
2025-08-24 0
李德生这个人,从小日子过得苦,1916年出生在河南新县一个穷山村,家里穷得叮当响,早年母亲没了,他就帮人放牛讨生活。1930年,年纪轻轻14岁,就投身...
2025-08-24 0
2025年中国光模块行业市场前景预测研究报告(简版)中商产业研究院 2025-08-22 08:49中商情报网讯:光模块作为数字经济的 “神经中枢”,...
2025-08-24 0
发表评论