python---多态
文章目录
- 多态的核心思想
- 多态的实现
- 1、继承与方法重写
- 2、鸭子类型(Duck Typing)
- 多态的优势
- 与抽象基类 (ABC) 的结合
多态(Polymorphism)是面向对象编程的三大核心特性之一(封装、继承、多态)。同一个方法或操作符,在不同的对象上可以有不同的行为。
多态的核心思想
核心思想是:你不需要关心一个对象具体是什么类型,只需要关心它有没有你要的方法或属性(即它是否“像”你需要的那个东西)。如果有,它就可以被调用。
这也就是著名的“鸭子测试”:“如果它走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子。”
多态的实现
在 Python 中,多态通常通过以下两种方式实现:
1、继承与方法重写
子类继承父类后,可以重写(Override)父类的方法,从而使得相同的方法名在不同的子类中有不同的实现。
class Animal:def speak(self):# 父类的方法通常不实现具体功能,或者提供一个基础实现/抛异常raise NotImplementedError("子类必须实现此方法")class Dog(Animal):def speak(self): # 重写父类的 speak 方法return "汪汪!"class Cat(Animal):def speak(self): # 重写父类的 speak 方法return "喵喵!"class Duck(Animal):def speak(self): # 重写父类的 speak 方法return "嘎嘎!"# 创建一个函数,它接受一个 Animal 类型的对象(或其子类)
def animal_talk(animal_obj):# 我们不关心 animal_obj 具体是哪种动物# 我们只关心它是否有 .speak() 方法print(animal_obj.speak())# 创建不同的对象
my_dog = Dog()
my_cat = Cat()
my_duck = Duck()# 调用同一个函数,传入不同的对象,产生不同的行为(多种形态)
animal_talk(my_dog) # 输出: 汪汪!
animal_talk(my_cat) # 输出: 喵喵!
animal_talk(my_duck) # 输出: 嘎嘎!
2、鸭子类型(Duck Typing)
Python 的多态不依赖于严格的继承关系。即使两个类完全没有继承同一个父类,只要它们有相同名称的方法,它们就可以被同样地对待。
class Dog:def speak(self):return "汪汪!"class Robot:# 一个机器人,它根本不是 Animal 的子类def speak(self):return "你好,主人!我是机器人。"class Car:# 一辆汽车,没有 speak 方法def run(self):return "引擎轰鸣!"# 同样的函数,不关心类型,只关心行为
def make_it_speak(entity):print(entity.speak())my_dog = Dog()
my_robot = Robot()
my_car = Car() # 这个对象没有 speak 方法make_it_speak(my_dog) # 输出: 汪汪!
make_it_speak(my_robot) # 输出: 你好,主人!我是机器人。# 尝试对 Car 调用会出错
make_it_speak(my_car) # AttributeError: 'Car' object has no attribute 'speak'
多态的优势
1、提高灵活性:代码可以处理多种不同类型的对象,只要它们遵循相同的接口(具有相同的方法名)。
2、提高可扩展性:如果要增加一个新的类,只需要确保这个新类实现了所需的方法(例如 speak),那么现有的函数(例如 animal_talk 或 make_it_speak)就可以立即处理这个新类的对象,而不需要修改函数本身的代码。这符合“开闭原则”(对扩展开放,对修改封闭)。
3、简化代码:使用者不需要写一大堆 if isinstance(obj, Dog)…else if isinstance(obj, Cat)… 这样的类型检查语句,代码更简洁、更通用。
与抽象基类 (ABC) 的结合
为了防止出现错误,我们会使用抽象基类来定义一种“协议”或“接口”,明确要求子类必须实现某些方法。
from abc import ABC, abstractmethodclass Speaker(ABC): # 继承 ABC,这是一个抽象基类@abstractmethoddef speak(self):pass # 抽象方法,没有实现class Dog(Speaker): # 现在 Dog 必须实现 speakdef speak(self):return "汪汪!"class Cat(Speaker): # Cat 也必须实现 speakdef speak(self):return "喵喵!"# 如果有一个类继承 Speaker 但没有实现 speak,在实例化时就会报错
class InvalidSpeaker(Speaker):pass# invalid = InvalidSpeaker() # 这行会报错:TypeError: Can't instantiate abstract class InvalidSpeaker with abstract method speak
抽象基类提供了一个严格的契约,但它仍然支持多态。任何继承自 Speaker 的类都保证有 speak 方法,因此 make_it_speak 函数可以安全地调用它。