多态性
【一】概要
- 多态是面向对象编程中的一个重要概念,指的是同一种操作作用于不同的对象上时,可以产生不同的行为。多态性允许同样的方法名在不同的对象上有不同的实现,这样可以提高代码的灵活性和可扩展性。
- 在多态的情况下,程序可以根据对象的类型调用相应的方法,而不需要知道具体对象的类型。这样,不同的类可以实现相同的接口或继承相同的父类,并提供各自的实现,使得代码更容易扩展和维护。
【二】常用方法
- 例:只要是动物就会有叫这个方法
- 使用abc模块,也叫抽象类,强制要求继承的子类必须包含父类的属性
| import abc |
| class Animal(metaclass = abc.ABCMeta): |
| @abc.abstractmethod |
| def speak(self): |
| pass |
| class Person(Animal): |
| def speak(self): |
| pass |
| |
| |
| Animal() |
- 不做强制限制,但需要自觉的遵从一些规范,如果你属于这个类,那么这个类共有的属性最好就加上
| class Animal(object): |
| pass |
| |
| class Person(Animal): |
| def speak(self): |
| pass |
| |
| class Cat(Animal): |
| |
| |
| def miaow(self): |
| pass |
| |
【三】详解
【1】继承与抽象
- 继承(Inheritance):
- 定义: 继承是一种机制,允许一个类(子类或派生类)获取另一个类(父类或基类)的属性和方法。
- 特点: 子类继承了父类的特征,包括属性和方法。这使得子类可以重用父类的代码,并在此基础上进行扩展或修改。
- 目的: 提高代码的重用性、可维护性和可扩展性。通过继承,可以建立类之间的层次结构,实现通用性和特定性的分离。
- 抽象(Abstraction):
- 定义: 抽象是一种思维方式,通过忽略或隐藏与问题无关的细节,突出问题的关键特征,从而提高问题的理解和解决效率。
- 特点: 抽象关注于问题的本质,将复杂的现实世界简化为关键的概念或模型。在编程中,抽象可以通过类和接口来实现,将对象的属性和行为抽象出来。
- 目的: 提高代码的理解和设计水平,降低复杂性,使代码更加清晰和易于维护。


【2】抽象类
- 抽象类是一种不能被实例化的类,其目的是为了被子类继承,并要求子类必须实现特定的方法或属性。抽象类通常包含抽象方法,这些方法在抽象类中被声明但没有提供具体的实现,而是由具体的子类来实现。抽象类可以提供一些共同的接口和结构,以确保子类具有一致的行为。
- 抽象类通过
ABC
模块来实现,使用@abstractmethod
装饰器声明抽象方法。子类必须实现所有抽象方法才能被实例化,否则会引发TypeError
。抽象类的主要作用是定义规范,强制要求子类实现特定的行为。
| import abc |
| class Person(metaclass=abc.ABCMeta): |
| '''【类Person】作为抽象类,只能被继承,不能被实例化''' |
| @abc.abstractmethod |
| def eat(self): |
| pass |
| |
| Person() |
【2.1】abc模块(abstarct class)
| import abc |
| class Person(metaclass=abc.ABCMeta): |
| '''【类Person】作为抽象类,只能被继承,不能被实例化''' |
| '''通过模块abc实现,凡继承【类Person】的类,都需要有与抽象类同样的方法''' |
| @abc.abstractmethod |
| def eat(self): |
| pass |
| @abc.abstractmethod |
| def drink(self): |
| pass |
| class Chinese(Person): |
| def eat(self): |
| pass |
| def drink(self): |
| pass |
| |
| |
| class English(Person): |
| '''如果继承了定义类,但是不重写继承的方法,将会报错''' |
| def eat(self): |
| pass |
| c = Chinese() |
| e = English() |
【2.1.1】具体案例
- 定义一个工具类,类下的对象是文件类型,都必须有读和写的功能
| import abc |
| |
| |
| class Tools(metaclass=abc.ABCMeta): |
| '''通过模块abc实现,凡继承【类Tools】的类,都需要有与抽象类同样的方法''' |
| |
| @abc.abstractmethod |
| def read(self, *args, **kwargs): |
| pass |
| |
| @abc.abstractmethod |
| def save(self, *args, **kwargs): |
| pass |
| |
| |
| |
| class Json(Tools): |
| |
| def read(self, path, mode='r'): |
| import json |
| with open(file=path, mode=mode) as f: |
| data = json.load(f) |
| return data |
| |
| def save(self, data, path, mode='w'): |
| import json |
| with open(file=path, mode=mode) as f1: |
| json.dump(data, f1) |
| return "保存成功" |
| |
| def json_own(self): |
| pass |
| |
| |
| |
| class Pickle(Tools): |
| |
| def read(self, path): |
| import pickle |
| data = pickle.load(path) |
| return data |
| |
| def save(self, data, path): |
| import pickle |
| pickle.dump(data, path) |
| return "保存成功" |
| |
| def pickle_own(self): |
| pass |
【2.2】通过抛出异常限制子类
| class Animal(object): |
| def speak(self): |
| raise Exception("请先实现speak功能!") |
| |
| |
| class Dog(Animal): |
| def speak(self): |
| print("汪!汪!") |
| |
| |
| class Cat(Animal): |
| pass |
| |
| |
| d = Dog() |
| d.speak() |
| |
| c = Cat() |
| c.speak() |
【3】多态
- 多态指的是一类事物有多种形态
- 水:气态水、液态水、固态水
- 动物:人、狗、猪、等都是动物的一种形态
【3.1】鸭子类型(duck-typing)
-
在Python中,上述使用abc模块的方法其实并没有过多的使用,更加崇尚的是使用“鸭子类型”的这种编程风格
-
鸭子类型(Duck Typing)是一种动态类型的概念,关注的是对象的行为而非其类型。该概念源于一个谚语:“如果它走起路来像鸭子,叫起来像鸭子,那么它就是鸭子。”
-
在鸭子类型中,一个对象的适用性不是基于它的类(或类型),而是基于它是否具有特定的方法、属性或行为。这种方法不依赖于继承或接口的实现,而是依赖于对象的实际状态和行为。
-
例如,如果一个对象具有像鸭子一样的quack
方法和swim
方法,那么它就可以被视为“鸭子”,即使它并没有继承自特定的鸭子类或接口。这种方式使得代码更加灵活,可以接受多种不同类型的对象,只要它们满足所需的行为。
| class Duck(): |
| def swim(self): |
| |
| pass |
| def quack(self): |
| |
| print("嘎嘎") |
| class DonaldDuck(): |
| '''唐老鸭''' |
| def swim(self): |
| |
| pass |
| def quack(self): |
| |
| print("嘎嘎") |
| |
| class Goose(): |
| '''鹅''' |
| def swim(self): |
| |
| pass |
| def quack(self): |
| |
| print("嘎嘎") |
| |
| |
| |
| """鸭子类型就是更多的关注的是对象的行为,而不是对象的类型""" |
【3.2】多态性的具体应用场景
(1)抽象类
| '''拿上述的Tools举例''' |
| import abc |
| |
| |
| class Tools(metaclass=abc.ABCMeta): |
| '''通过模块abc实现,凡继承【类Tools】的类,都需要有与抽象类同样的方法''' |
| |
| @abc.abstractmethod |
| def read(self, *args, **kwargs): |
| pass |
| |
| @abc.abstractmethod |
| def save(self, *args, **kwargs): |
| pass |
| |
| |
| |
| class Json(Tools): |
| |
| def read(self, path, mode='r'): |
| import json |
| with open(file=path, mode=mode) as f: |
| data = json.load(f) |
| return data |
| |
| def save(self, data, path, mode='w'): |
| import json |
| with open(file=path, mode=mode) as f1: |
| json.dump(data, f1) |
| return "保存成功" |
| |
| def json_own(self): |
| pass |
| |
| |
| |
| class Pickle(Tools): |
| |
| def read(self, path): |
| import pickle |
| with open(path, 'rb') as fp: |
| data = pickle.load(fp) |
| return data |
| |
| def save(self, data, path): |
| import pickle |
| with open(path, 'wb') as fp: |
| pickle.dump(data, fp) |
| return "保存成功" |
| |
| def pickle_own(self): |
| pass |
| |
- 当我们需要调用工具时,可以通过定义一个函数来实现调用
| def file_handler(tag, file_obj, path, data=None): |
| if tag == 'read': |
| return file_obj.read(path) |
| elif tag == 'save': |
| return file_obj.save(data, path) |
| |
| |
| json = Json() |
| pickle = Pickle() |
| |
| file_handler('save', json, '1.json', data='json') |
| file_handler('read', json, '1.json') |
| |
| |
| file_handler('save', pickle, 'test', data='pickle') |
| file_handler('read', pickle, 'test') |
(2)多态性
| class Animal(object): |
| pass |
| |
| class Dog(Animal): |
| def speak(self): |
| print("汪!汪!") |
| |
| class Cat(Animal): |
| def speak(self): |
| print("喵喵~") |
| |
| |
| def speak_animal(animal): |
| animal.speak() |
| |
| |
| cat = Cat() |
| dog = Dog() |
| speak_animal(cat) |
| speak_animal(dog) |
| |
| |
- Python中的内置函数,也能体现多态,比如
len()
len()
方法,是许多数据类型都可以调用的方法
| str1 = 'str' |
| list1 = [1, 2, 3] |
| dict1 = {1: 1, 2: 2} |
| set1 = {1, 2, 3} |
| tuple1 = (1, 2, 3) |
| |
| print(len(str1)) |
| print(len(list1)) |
| print(len(dict1)) |
| print(len(set1)) |
| print(len(tuple1)) |
| |
| '''其实就相当于一个函数''' |
| def my_len(obj): |
| |
| return obj.__len__() |
| |
| print(my_len(str1)) |
| print(my_len(list1)) |
| print(my_len(dict1)) |
| print(my_len(set1)) |
| print(my_len(tuple1)) |
<class 'list'>
等以上可以使用len()
方法的数据类型中,均有__len__
方法

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了