当前位置:首页>python>python面向对象编程(二)——继承与多态

python面向对象编程(二)——继承与多态

  • 2026-09-08 05:06:17
python面向对象编程(二)——继承与多态

本周目标

  • 理解继承(Inheritance) 的概念,学会如何从父类派生子类
  • 掌握方法重写(Override) 和 super() 的用法
  • 理解多态(Polymorphism) 的核心思想——“同一个接口,不同实现”
  • 掌握常用的特殊方法(Magic Methods),如 __str__、__repr__、__add__
  • 完成实战项目:动物继承体系 + 动物园管理系统

一、为什么需要继承?

继承的核心价值在于代码复用和扩展性:

  • 代码复用
    子类可以自动拥有父类的所有属性和方法,无需重复编写
  • 扩展性
    子类可以在父类的基础上增加新的属性和方法,或重写父类的方法来改变行为
  • 多态的基础
    继承是实现多态的前提

在 AI 领域,继承无处不在:

  • PyTorch 中,你定义的每一个神经网络模型都继承自 torch.nn.Module,然后只需重写 forward() 方法
  • 数据处理中,你可以定义 BaseDataset 基类,然后派生出 ImageDataset、TextDataset 等子类
  • 训练流程中,你可以定义 BaseTrainer,然后派生出 CNNTrainer、LSTMTrainer 等

二、继承的基本语法

1. 继承的定义

使用 class 子类名(父类名): 来声明继承关系:

# 父类(基类)classAnimal:def__init__(self, name, age):self.name = nameself.age = agedefeat(self):print(f"{self.name} 正在吃东西")defsleep(self):print(f"{self.name} 正在睡觉")# 子类(派生类)classDog(Animal):defbark(self):print(f"{self.name} 汪汪叫!")# 创建子类对象dog = Dog("旺财", 3)dog.eat()    # 从父类继承的方法dog.sleep()  # 从父类继承的方法dog.bark()   # 子类自己的方法

💡 术语:父类也叫基类(Base Class) 或超类(Superclass);子类也叫派生类(Derived Class)。

2. super() —— 调用父类的方法

当子类需要执行父类的初始化逻辑时,使用 super().__init__(...) 调用父类的构造方法:

classAnimal:def__init__(self, name, age):self.name = nameself.age = agedefspeak(self):return"发出声音"classCat(Animal):def__init__(self, name, age, color):super().__init__(name, age)   # 调用父类的 __init__self.color = color            # 新增子类自己的属性defspeak(self):return"喵喵喵"# 重写父类方法cat = Cat("咪咪", 2, "橘色")print(cat.name)      # 咪咪(来自父类)print(cat.color)     # 橘色(子类新增)print(cat.speak())   # 喵喵喵(重写后)

⚠️ 重要:即使子类没有显式调用 super().__init__(),Python 也会自动调用父类的无参构造方法(如果存在)。但一旦子类定义了 __init__,就必须手动调用 super().__init__() 来初始化父类的属性,否则父类的属性不会被正确设置。

三、方法重写(Override)—— 子类定制自己的行为

子类可以对父类的方法进行重写(Override),即重新定义方法的实现:

classBird(Animal):def__init__(self, name, age, wing_span):super().__init__(name, age)self.wing_span = wing_span# 重写 speak 方法defspeak(self):return"叽叽喳喳"# 重写 eat 方法,增加额外行为defeat(self):super().eat()  # 先执行父类的 eatprint(f"{self.name} 吃完后啄了啄羽毛")bird = Bird("小翠", 1, 20)print(bird.speak())   # 叽叽喳喳bird.eat()# 输出:# 小翠 正在吃东西# 小翠 吃完后啄了啄羽毛

重写时使用 super() 调用父类方法

子类重写方法时,往往希望在父类逻辑的基础上增加功能,而不是完全覆盖。这时可以用 super().方法名() 调用父类版本:

classRobot:defwork(self):print("机器人正在工作")classAIChatRobot(Robot):defwork(self):super().work()            # 调用父类的工作逻辑print("并且能进行智能对话")  # 增加新功能robot = AIChatRobot()robot.work()# 输出:# 机器人正在工作# 并且能进行智能对话

四、多态(Polymorphism)——“一个接口,多种形态”

1. 什么是多态?

多态是指同一个方法名,在不同的类中可以有完全不同的实现。调用者不需要关心对象的实际类型,只需要调用相同的方法名,程序会自动根据对象类型执行对应的版本。

2. 多态的经典示例

classAnimal:defspeak(self):pass# 抽象方法,由子类实现classDog(Animal):defspeak(self):return"汪汪"classCat(Animal):defspeak(self):return"喵喵"classDuck(Animal):defspeak(self):return"嘎嘎"defmake_animal_speak(animal):"""多态函数:不管传入什么动物,都调用 speak 方法"""print(f"{animal.__class__.__name__}: {animal.speak()}")# 使用多态animals = [Dog(), Cat(), Duck()]for animal in animals:    make_animal_speak(animal)# 输出:# Dog: 汪汪# Cat: 喵喵# Duck: 嘎嘎

💡 多态的价值:新增一个 Pig 类,只要它实现了 speak() 方法,make_animal_speak 函数无需任何修改,就能直接支持它。这符合开闭原则(对扩展开放,对修改关闭)。

3. 多态在 AI 中的应用场景

在训练模型时,我们可能使用不同的模型架构(CNN、RNN、Transformer),但它们都有相同的接口 train()、evaluate()、predict()。训练脚本可以接受任何模型对象,调用相同的方法,实现统一的训练流程——这就是多态的力量。

classBaseModel:deftrain(self, data):raise NotImplementedErrordefpredict(self, x):raise NotImplementedErrorclassCNNModel(BaseModel):deftrain(self, data):print("CNN 训练中...")defpredict(self, x):print("CNN 预测中...")classRNNModel(BaseModel):deftrain(self, data):print("RNN 训练中...")defpredict(self, x):print("RNN 预测中...")defrun_experiment(model, data):    model.train(data)    model.predict(data)# 可以传入任意模型run_experiment(CNNModel(), "图片数据")run_experiment(RNNModel(), "序列数据")

五、特殊方法(Magic Methods / Dunder Methods)

Python 类中有许多以双下划线开头和结尾的方法,被称为特殊方法(Magic Methods)。它们定义了类的行为,让对象能够响应 Python 内置操作。

1. __str__ 和 __repr__ —— 对象的字符串表示

  • __str__
    :给用户看的友好字符串(通过 print() 或 str() 触发)
  • __repr__
    :给开发者看的精确字符串(通过 repr() 或直接输入对象触发)
classBook:def__init__(self, title, author, price):self.title = titleself.author = authorself.price = pricedef__str__(self):returnf"《{self.title}》作者:{self.author},价格:¥{self.price}"def__repr__(self):returnf"Book('{self.title}', '{self.author}', {self.price})"book = Book("Python编程", "张三", 59)print(book)          # 调用 __str__: 《Python编程》作者:张三,价格:¥59print(repr(book))    # 调用 __repr__: Book('Python编程', '张三', 59)

2. __len__ —— 让对象支持 len()

classLibrary:def__init__(self):self.books = []defadd_book(self, book):self.books.append(book)def__len__(self):returnlen(self.books)lib = Library()lib.add_book(Book("A", "a", 10))lib.add_book(Book("B", "b", 20))print(len(lib))   # 2

3. 运算符重载(如 __add__、__eq__ 等)

通过特殊方法,可以让自定义对象支持 +、== 等运算符:

classVector:def__init__(self, x, y):self.x = xself.y = ydef__add__(self, other):"""向量加法"""ifnotisinstance(other, Vector):raise TypeError("只能与 Vector 相加")return Vector(self.x + other.x, self.y + other.y)def__eq__(self, other):"""向量相等判断"""returnself.x == other.x andself.y == other.ydef__str__(self):returnf"Vector({self.x}, {self.y})"v1 = Vector(1, 2)v2 = Vector(3, 4)v3 = v1 + v2        # 调用 __add__print(v3)           # Vector(4, 6)print(v1 == v2)     # False

💡 常见特殊方法:

  • __add__
    +
  • __sub__
    -
  • __mul__
    *
  • __truediv__
    /
  • __eq__
    ==
  • __lt__
    <
  • __getitem__
    索引访问 obj[key]
  • __setitem__
    索引赋值 obj[key] = value
  • __call__
    让对象可以像函数一样调用

六、实战项目:动物继承体系 + 动物园管理系统

我们将构建一个完整的动物继承体系,展示继承、重写和多态,并实现一个简单的动物园管理程序。

类设计

Animal(抽象基类)├── __init__: name, age├── speak(): 抽象方法├── eat(): 通用实现├── __str__: 显示信息Mammal(哺乳动物) extends Animal├── __init__: name, age, fur_color├── give_birth(): 胎生Bird(鸟类) extends Animal├── __init__: name, age, wing_span├── fly(): 飞行Reptile(爬行动物) extends Animal├── __init__: name, age, is_venomous├── crawl(): 爬行Dog(狗) extends Mammal├── speak(): "汪汪"├── wag_tail(): 摇尾巴Cat(猫) extends Mammal├── speak(): "喵喵"├── purr(): 打呼噜Eagle(鹰) extends Bird├── speak(): "嘶鸣"├── hunt(): 捕猎Zoo(动物园) 管理所有动物├── add_animal()├── list_animals()├── make_all_speak()└── find_by_type()

完整代码

# ============================================# 动物继承体系 + 动物园管理系统# 知识点:继承、方法重写、多态、特殊方法# ============================================classAnimal:"""动物基类"""def__init__(self, name, age):self.name = nameself.age = agedefeat(self):print(f"{self.name} 正在进食")defspeak(self):# 抽象方法,子类必须重写raise NotImplementedError("子类必须实现 speak 方法")def__str__(self):returnf"{self.__class__.__name__}({self.name}, {self.age}岁)"def__repr__(self):returnself.__str__()classMammal(Animal):"""哺乳动物类"""def__init__(self, name, age, fur_color):super().__init__(name, age)self.fur_color = fur_colordefgive_birth(self):print(f"{self.name} 生了一只小宝宝")classBird(Animal):"""鸟类"""def__init__(self, name, age, wing_span):super().__init__(name, age)self.wing_span = wing_span  # 翼展(厘米)deffly(self):print(f"{self.name} 展翅高飞,翼展 {self.wing_span} cm")classReptile(Animal):"""爬行动物类"""def__init__(self, name, age, is_venomous):super().__init__(name, age)self.is_venomous = is_venomousdefcrawl(self):print(f"{self.name} 正在爬行")# ---------- 具体动物子类 ----------classDog(Mammal):defspeak(self):return"汪汪!"defwag_tail(self):print(f"{self.name} 摇着尾巴,很开心!")classCat(Mammal):defspeak(self):return"喵喵~"defpurr(self):print(f"{self.name} 发出咕噜咕噜的声音")classEagle(Bird):defspeak(self):return"嘶鸣——"defhunt(self):print(f"{self.name} 正在捕猎")classSnake(Reptile):defspeak(self):return"嘶嘶嘶..."defeat(self):# 重写 eat 方法,增加蛇特有的进食行为super().eat()print(f"{self.name} 一口吞下了猎物!")# ---------- 动物园类 ----------classZoo:"""动物园管理类"""def__init__(self, name):self.name = nameself.animals = []  # 存放所有动物对象defadd_animal(self, animal):"""添加动物"""self.animals.append(animal)print(f"✅ {animal.name} 已加入 {self.name}")deflist_animals(self):"""列出所有动物"""ifnotself.animals:print("🏚️ 动物园暂时没有动物")returnprint(f"\n{'='*50}")print(f"        🦁 {self.name} 动物名录")print(f"        总数:{len(self.animals)} 只")print(f"{'='*50}")for i, animal inenumerate(self.animals, 1):            type_name = animal.__class__.__name__print(f"{i}. {type_name} | {animal} | 叫声:{animal.speak()}")print(f"{'='*50}")defmake_all_speak(self):"""让所有动物叫一遍(多态演示)"""print(f"\n🔊 {self.name} 大合唱:")for animal inself.animals:print(f"  {animal.name}:{animal.speak()}")deffind_by_type(self, class_name):"""根据类型名称查找动物"""        result = []for animal inself.animals:if animal.__class__.__name__ == class_name:                result.append(animal)return resultdef__len__(self):"""返回动物总数"""returnlen(self.animals)def__str__(self):returnf"🏛️ {self.name}({len(self.animals)} 只动物)"# ========== 测试和演示 ==========if __name__ == "__main__":# 创建动物园    zoo = Zoo("幸福动物园")print(f"欢迎来到 {zoo}!")# 创建各种动物    dog = Dog("旺财", 3, "金色")    cat = Cat("咪咪", 2, "橘色")    eagle = Eagle("小鹰", 5, 180)    snake = Snake("小青", 1, True)# 添加到动物园print("\n--- 添加动物 ---")    zoo.add_animal(dog)    zoo.add_animal(cat)    zoo.add_animal(eagle)    zoo.add_animal(snake)# 展示所有动物    zoo.list_animals()# 多态演示:所有动物一起叫    zoo.make_all_speak()# 演示父类和子类方法的调用print("\n--- 行为演示 ---")    dog.wag_tail()    cat.purr()    eagle.hunt()    snake.eat()  # 重写了 eat 方法# 特殊方法演示print(f"\n动物园大小:{len(zoo)} 只动物")print(zoo)   # 调用 __str__# 按类型查找print("\n--- 查找哺乳动物 ---")    mammals = zoo.find_by_type("Mammal")for m in mammals:print(f"  {m.name}")

运行效果示例

欢迎来到 🏛️ 幸福动物园(0 只动物)!--- 添加动物 ---✅ 旺财 已加入 幸福动物园✅ 咪咪 已加入 幸福动物园✅ 小鹰 已加入 幸福动物园✅ 小青 已加入 幸福动物园==================================================        🦁 幸福动物园 动物名录        总数:4 只==================================================1. Dog | Dog(旺财, 3岁) | 叫声:汪汪!2. Cat | Cat(咪咪, 2岁) | 叫声:喵喵~3. Eagle | Eagle(小鹰, 5岁) | 叫声:嘶鸣——4. Snake | Snake(小青, 1岁) | 叫声:嘶嘶嘶...==================================================🔊 幸福动物园 大合唱:  旺财:汪汪!  咪咪:喵喵~  小鹰:嘶鸣——  小青:嘶嘶嘶...--- 行为演示 ---旺财 摇着尾巴,很开心!咪咪 发出咕噜咕噜的声音小鹰 正在捕猎小青 正在进食小青 一口吞下了猎物!动物园大小:4 只动物🏛️ 幸福动物园(4 只动物)--- 查找哺乳动物 ---  旺财  咪咪

本周小结

本周我们深入了面向对象的核心——继承与多态:

知识点
核心要点
继承
子类 class 子类(父类): 自动拥有父类的属性和方法
super()
在子类中调用父类的方法(尤其 __init__)
方法重写
子类重新定义父类的方法,改变或增强行为
多态
相同的方法名在不同的类中有不同的实现,调用者无需关心具体类型
鸭子类型
Python 不强制继承,只要对象有相应方法就能使用
特殊方法__str__
、__repr__、__add__ 等,让对象支持内置操作

继承和多态是面向对象编程的“灵魂”。🚀

最新文章

随机文章