1. 什么是多态?
简单来说,多态就是“同一个方法,不同实现”。当调用一个方法时,具体执行哪个版本的代码取决于调用该方法的对象类型。即使不知道对象的精确类型,只要它支持所需的方法,程序就能正常运行。
2. 通过继承实现多态
最常见的多态实现方式是通过继承和方法重写。定义一个基类,其中包含一个方法(通常是一个占位符或提供默认实现),然后让子类重写这个方法以提供特定的行为。
🎯示例:动物叫声
假设有一个Animal基类,它定义了一个speak()方法。不同的动物子类(如Dog和Cat)重写speak()方法,返回不同的叫声。
class Animal: def speak(self): # 基类中的方法可以是空实现,也可以抛出异常以强制子类重写 raise NotImplementedError("Subclass must implement this method")class Dog(Animal): def speak(self): return "Woof!"class Cat(Animal): def speak(self): return "Meow!"# 一个接收任何动物对象并调用其speak方法的函数def animal_sound(animal): print(animal.speak())# 创建对象dog = Dog()cat = Cat()# 调用函数,传入不同的对象animal_sound(dog) # 输出: Woof!animal_sound(cat) # 输出: Meow!
当我们执行 animal_sound(dog) 时,animal 参数指向一个 Dog 对象。当程序运行到 animal.speak() 时,Python 会去查找 dog 对象的 speak 方法。因为 dog 是 Dog 类的实例,而 Dog 类中定义了自己的 speak 方法(返回 "Woof!"),所以 Python 就调用了这个版本。
同样,当我们执行 animal_sound(cat) 时,animal 指向一个 Cat 对象,Python 就会查找 Cat 类中的 speak 方法,然后调用它。
这个“查找并调用正确方法”的过程是在运行时由 Python 自动完成的,不需要我们在代码中显式地判断类型。
在这个例子中,animal_sound函数并不知道传入的究竟是Dog还是Cat,它只关心对象有没有speak方法。运行时,Python会根据对象的实际类型自动调用正确版本的speak方法,这就是多态的体现。
🧰语法要点
class:定义类的关键字。
class Dog(Animal)::类的继承,Dog继承自Animal。
def speak(self)::定义方法。
raise NotImplementedError:抛出异常,提示子类必须重写该方法。
函数定义与调用:如def animal_sound(animal):和animal_sound(dog)。
对象实例化:dog = Dog()。
3. 鸭子类型:Python风格的多态
Python是一种动态类型语言,它推崇“鸭子类型”(duck typing):“如果它走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子。”这意味着我们并不需要严格的继承关系,只要对象实现了所需的方法,它就可以被当作某种类型来使用。
🧭示例1:模拟鸭子叫声
我们定义两个完全没有继承关系的类:Duck和Person。它们都有quack方法,但实现不同。
class Duck: def quack(self): print("Quack!")class Person: def quack(self): print("I'm quacking like a duck!")def make_it_quack(thing): # 我们只关心thing有没有quack方法 thing.quack()duck = Duck()person = Person()make_it_quack(duck) # 输出: Quack!make_it_quack(person) # 输出: I'm quacking like a duck!
这里make_it_quack函数接受任何具有quack方法的对象,并调用它。Duck和Person并没有共同的父类,但都实现了quack,因此它们都能作为参数传入。这正是鸭子类型的魅力,也是Python多态的另一种体现。
🌅语法要点
示例2:鸟类的飞行行为
以下例子展示多态如何工作——无需继承,只要对象有fly()方法,就能被统一处理。
🚀步骤:
# 定义会飞的鸟类class Bird: def fly(self): print("Bird is flying high!")# 定义企鹅类(不会飞,但提供fly方法)class Penguin: def fly(self): print("Penguin can't fly, but I swim!")# 多态函数:只关心对象是否有fly方法def make_fly(bird): bird.fly() # 调用传入对象的fly方法# 测试多态sparrow = Bird() # 麻雀对象penguin = Penguin() # 企鹅对象make_fly(sparrow) # 输出: Bird is flying high!make_fly(penguin) # 输出: Penguin can't fly, but I swim!
🧩为什么这个例子正确?
语法无误:所有类方法都包含self,对象实例化正确,调用方式标准。
多态体现:
make_fly() 不关心传入的是Bird还是Penguin,只检查fly()方法是否存在。
两个类的fly()实现不同,但函数能统一处理。
简单性:仅用2个类、1个函数,无继承、无复杂逻辑。
4. 多态的优势
代码复用:可以编写通用函数(如上面的animal_sound和make_it_quack),减少重复代码。
可扩展性:新增类时,只要保证它实现了所需的方法,就能无缝接入现有逻辑,无需修改已有函数。
简化接口:调用者只需知道对象支持哪些方法,而不必关心对象的具体类型。