多态(polymorphism)是“同一个调用,对不同对象产生各自行为”。调用方写一次 employee.get_salary(),全职员工按基本工资加奖金计算,兼职员工按时薪乘工时计算。循环不需要堆叠类型判断,职责留在各个对象内部。
如果这些对象共享父类,共同方法就像一份明确约定;Python 还支持鸭子类型:即使没有共同父类,只要对象提供调用方需要的方法,也能参与同一段代码。
同名方法,不同实现
class Employee:
def get_salary(self):
raise NotImplementedError
class FullTimeEmployee(Employee):
def __init__(self, name, salary, bonus):
self.name, self.salary, self.bonus = name, salary, bonus
def get_salary(self):
return self.salary + self.bonus
class PartTimeEmployee(Employee):
def __init__(self, name, wage, hours):
self.name, self.wage, self.hours = name, wage, hours
def get_salary(self):
return self.wage * self.hours
employees = [FullTimeEmployee("Alice", 5783, 173),
PartTimeEmployee("Bob", 150, 15)]
for employee in employees:
print(employee.get_salary())互动实验
多态工资站:同一段循环,不同的计算
访问权限PRO
PRO EXCLUSIVE探索不止于此
尊享 Pro 权益解锁完整互动实验、进阶解析与精选参考答案。
知识测验
题目
同一条 get_salary() 调用为何会使用不同公式?
知识测验
题目
多态给调用方带来的主要好处是什么?
鸭子类型与可扩展性
Report、Invoice 和 GradeSheet 不一定属于同一种事物,但都可以提供 export()。export_all() 只依赖这个行为。以后新增 Receipt,只要也实现 export,就无需修改循环。代价是:如果对象缺少方法,错误会在运行到调用处时出现,因此命名约定、测试和清晰文档很重要。
鸭子类型的直觉是:“如果它走起来像鸭子、叫起来像鸭子,就可以按鸭子使用。”代码关心能力,而不只关心身份。
def export_all(items):
for item in items:
print(item.export())知识测验
题目
鸭子类型首先关注什么?
知识测验
题目
给 export_all() 增加新类型,最关键的条件是什么?
动手练习
统一计算不同员工工资
- 实现 FullTimeEmployee 和 PartTimeEmployee。
- 两者都提供 get_name() 与 get_salary()。
- 放进同一列表,只用一个循环打印姓名和工资。
动手练习
鸭子类型批量导出
- 创建 Report、Invoice、GradeSheet,彼此无需继承。
- 每个类都实现 export() 并返回不同文本。
- 编写 export_all(items),只用 item.export()。
- 新增 Receipt 类,证明 export_all 无需修改。